Skip to content

Pending Review

Pending Review from User Experience (UX)

Checkbox Component

Overview

The PWC Checkbox component provides a binary selection interface for forms and user preferences. Built with Lit web components, it offers full accessibility support, validation integration, and consistent visual feedback for checked and unchecked states.

Core Capabilities

  • Binary Selection - True/false selection with clear visual indication of checked and unchecked states

  • Form Integration - Native form field behavior with validation, required state, and error message display

  • Accessibility Focus - Full keyboard navigation with proper ARIA attributes and screen reader compatibility

  • Visual Feedback - Checkmark icon display with inverse color styling for selected state indication

  • Loading States - Skeleton loading animation during form loading and async operations

  • Validation Support - Built-in validation with required field checking and custom validation message display

When to use Checkbox:

  • Binary choices where users need to opt-in or opt-out of specific options or features

  • Terms and conditions acceptance, newsletter subscriptions, and preference settings

  • Multi-selection scenarios where users can choose multiple independent options

  • Form fields requiring explicit user confirmation before proceeding with actions

When not to use Checkbox:

  • Single-choice selections where only one option should be active - use radio buttons instead

  • Toggle switches for immediate state changes that don't require form submission

  • Navigation or action triggers that should use buttons or links for better semantics

Basic Implementation

import { PwcCheckbox } from "@progress-i360/pwc-react";

function MyComponent() {
  const handleAcceptTerms = (event) => {
    console.log('Terms accepted:', event.detail);
  };

  return (
    <>
      <PwcCheckbox
        label="I accept the terms and conditions"
        name="acceptTerms"
        required
        onChange={handleAcceptTerms}
      />

      <PwcCheckbox
        label="Subscribe to newsletter"
        name="newsletter"
        hint="Receive updates and promotions"
      />
    </>
  );
}
import { useEffect, useRef, useState } from 'react';
import '@progress-i360/progress-web-components/body';
import '@progress-i360/progress-web-components/checkbox';

type CheckboxElement = HTMLElement & { value?: boolean; disabled?: boolean };
type PreferenceState = { notifications: boolean; terms: boolean; newsletter: boolean };

function PreferenceSettings() {
  const notificationsRef = useRef<CheckboxElement | null>(null);
  const termsRef = useRef<CheckboxElement | null>(null);
  const newsletterRef = useRef<CheckboxElement | null>(null);

  const [preferences, setPreferences] = useState<PreferenceState>({
    notifications: false,
    terms: false,
    newsletter: false
  });

  useEffect(() => {
    const notificationsElement = notificationsRef.current;
    const termsElement = termsRef.current;
    const newsletterElement = newsletterRef.current;

    if (!notificationsElement || !termsElement || !newsletterElement) {
      return;
    }

    const handleNotifications = (event: Event) => {
      const detail = (event as CustomEvent<boolean>).detail;
      setPreferences((prev) => {
        const next = { ...prev, notifications: detail };
        if (!detail) {
          next.newsletter = false;
        }
        return next;
      });
    };

    const handleTerms = (event: Event) => {
      const detail = (event as CustomEvent<boolean>).detail;
      setPreferences((prev) => ({ ...prev, terms: detail }));
    };

    const handleNewsletter = (event: Event) => {
      const detail = (event as CustomEvent<boolean>).detail;
      setPreferences((prev) => ({ ...prev, newsletter: detail }));
    };

    notificationsElement.addEventListener('pwc-change', handleNotifications);
    termsElement.addEventListener('pwc-change', handleTerms);
    newsletterElement.addEventListener('pwc-change', handleNewsletter);

    return () => {
      notificationsElement.removeEventListener('pwc-change', handleNotifications);
      termsElement.removeEventListener('pwc-change', handleTerms);
      newsletterElement.removeEventListener('pwc-change', handleNewsletter);
    };
  }, []);

  useEffect(() => {
    if (notificationsRef.current) {
      notificationsRef.current.value = preferences.notifications;
    }
    if (termsRef.current) {
      termsRef.current.value = preferences.terms;
    }
    if (newsletterRef.current) {
      newsletterRef.current.value = preferences.newsletter;
      newsletterRef.current.disabled = !preferences.notifications;
    }
  }, [preferences]);

  const selectedCount = Object.values(preferences).filter(Boolean).length;

  return (
    <div>
      <pwc-checkbox
        ref={notificationsRef}
        label="Enable notifications"
        name="notifications"
      ></pwc-checkbox>
      <pwc-checkbox
        ref={termsRef}
        label="Accept terms and conditions"
        name="terms"
        required
      ></pwc-checkbox>
      <pwc-checkbox
        ref={newsletterRef}
        label="Subscribe to newsletter"
        name="newsletter"
        hint="Receive updates and promotions"
      ></pwc-checkbox>
      <pwc-body
        content={`Selected: ${selectedCount}/3`}
        color="subtle"
        size="xs"
      ></pwc-body>
    </div>
  );
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/body";
import "@progress-i360/progress-web-components/button";
import "@progress-i360/progress-web-components/checkbox";
import "@progress-i360/progress-web-components/flex";
import "@progress-i360/progress-web-components/heading";

@Component({
  selector: 'checkbox-demo',
  template: `
    <pwc-flex direction="column" gap="m" padding="m">
      <pwc-heading content="User Preferences" size="l"></pwc-heading>
      <pwc-flex direction="column" gap="s">
        <pwc-checkbox 
          label="Enable notifications" 
          [value]="notificationsEnabled"
          (pwc-change)="handleNotificationChange($event)">
        </pwc-checkbox>
        <pwc-checkbox 
          label="Accept terms and conditions" 
          [value]="termsAccepted"
          [required]="true"
          (pwc-change)="handleTermsChange($event)">
        </pwc-checkbox>
        <pwc-checkbox 
          label="Subscribe to newsletter" 
          [value]="newsletterSubscribed"
          [disabled]="!notificationsEnabled"
          (pwc-change)="handleNewsletterChange($event)">
        </pwc-checkbox>
      </pwc-flex>
      <pwc-flex gap="s">
        <pwc-button label="Select All" variant="outline" (pwc-click)="selectAll()"></pwc-button>
        <pwc-button label="Clear All" variant="clear" (pwc-click)="clearAll()"></pwc-button>
        <pwc-button label="Submit" variant="primary" [disabled]="!canSubmit()" (pwc-click)="submit()"></pwc-button>
      </pwc-flex>
      <pwc-body [content]="getStatusText()" color="subtle" size="xs"></pwc-body>
    </pwc-flex>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class CheckboxDemo {
  notificationsEnabled = false;
  termsAccepted = false;
  newsletterSubscribed = false;
  submissionCount = 0;

  handleNotificationChange(e: Event) {
    const ce = (e as CustomEvent);
    this.notificationsEnabled = ce.detail;
    // Auto-disable newsletter if notifications are disabled
    if (!this.notificationsEnabled) {
      this.newsletterSubscribed = false;
    }
  }

  handleTermsChange(e: Event) {
    const ce = (e as CustomEvent);
    this.termsAccepted = ce.detail;
  }

  handleNewsletterChange(e: Event) {
    const ce = (e as CustomEvent);
    this.newsletterSubscribed = ce.detail;
  }

  selectAll() {
    this.notificationsEnabled = true;
    this.termsAccepted = true;
    this.newsletterSubscribed = true;
  }

  clearAll() {
    this.notificationsEnabled = false;
    this.termsAccepted = false;
    this.newsletterSubscribed = false;
  }

  canSubmit() {
    return this.termsAccepted; // Terms are required
  }

  submit() {
    if (this.canSubmit()) {
      this.submissionCount++;
    }
  }

  getStatusText() {
    const selected = [this.notificationsEnabled, this.termsAccepted, this.newsletterSubscribed].filter(Boolean).length;
    return `Selected: ${selected}/3, Submissions: ${this.submissionCount}, Valid: ${this.canSubmit() ? 'Yes' : 'No'}`;
  }
}
import '@progress-i360/progress-web-components/checkbox';

const checkbox = document.createElement('pwc-checkbox');
checkbox.setAttribute('label', 'Accept terms and conditions');
checkbox.setAttribute('name', 'terms');
checkbox.required = true;

checkbox.addEventListener('pwc-change', (event) => {
  console.log('Checkbox checked:', event.detail);
});

document.body.appendChild(checkbox);

Usage Patterns

  • Form Agreements - Terms of service, privacy policy acceptance, and legal compliance checkboxes with required validation

  • User Preferences - Settings and configuration options that users can enable or disable independently

  • Multi-Selection Lists - Allow users to select multiple items from a list where each option is independent

  • Feature Toggles - Enable or disable specific application features and functionality within forms and settings

Best Practices

Content Strategy Guidelines

  • Clear Labels - Use descriptive, action-oriented labels that clearly state what the user is agreeing to or enabling

  • Helpful Hints - Provide additional context through hint text to clarify the impact of checkbox selections

  • Logical Grouping - Group related checkboxes together and use consistent labeling patterns

  • Required Indicators - Clearly mark required checkboxes and explain why they are necessary

Performance Optimization

  • Event Handling - Use efficient event delegation patterns for multiple checkboxes to reduce memory usage

  • State Management - Implement proper state management to avoid unnecessary re-renders on checkbox changes

  • Validation Timing - Validate checkboxes on appropriate events (blur, change) rather than on every input

  • Loading States - Show skeleton loaders during form initialization to improve perceived performance

Integration Architecture

  • Form Context - Leverage form integration for validation, submission handling, and error state management

  • Accessibility Standards - Ensure proper keyboard navigation, focus management, and screen reader support

  • Design System - Use consistent spacing, colors, and typography tokens from the design system

  • Data Binding - Implement efficient two-way data binding patterns for checkbox state management

Common Use Cases

  • Terms of service acceptance for account registration and service usage

  • Privacy policy acknowledgment for data collection and processing consent

  • Cookie policy acceptance for website tracking and analytics permissions

User Preferences

  • Notification settings for emails, push notifications, and in-app alerts

  • Display preferences for themes, language selection, and interface customization

  • Privacy settings for profile visibility, data sharing, and communication preferences

Feature Configuration

  • Optional feature enablement for advanced functionality and beta features

  • Integration settings for third-party services and external application connections

  • Backup and sync preferences for data storage and cross-device synchronization

Troubleshooting

Common Issues

Actions Not Triggering

Symptoms: Checkbox clicks don't update values or fire change events

Solutions:

  • Verify pwc-change event listeners are properly attached to checkbox elements

  • Check if checkbox is disabled or form is in loading state preventing interactions

  • Ensure proper event propagation and that parent elements aren't intercepting events

Actions Not Visible

Symptoms: Checkboxes don't appear or visual states don't update correctly

Solutions:

  • Confirm checkbox component is imported and registered correctly in the application

  • Check CSS styling and z-index values that might be hiding checkbox elements

  • Verify design tokens are loaded for proper background and border colors

Layout Issues

Symptoms: Checkboxes appear misaligned or with incorrect spacing relative to labels

Solutions:

  • Check parent container flex properties and alignment settings

  • Ensure proper margin and padding values are applied consistently

  • Verify label container styling doesn't conflict with checkbox positioning

Icon Problems

Symptoms: Checkmark icons don't appear in checked state or display with wrong colors

Solutions:

  • Confirm icon system is properly loaded and checkmark icon is available

  • Check color token values for inverse and disabled icon states

  • Verify checkbox checked state styling applies proper background colors

Implementation Support

  • Form Integration - Pattern guidance for validation, error handling, and submission workflows with checkbox fields

  • Accessibility Compliance - WCAG implementation strategies and screen reader optimization for checkbox interactions

  • Design System Integration - Token usage, theming, and consistent styling across checkbox implementations

Resources

Storybook Documentation

For comprehensive API documentation, interactive examples, and testing tools: 📖 View Complete API Documentation in Storybook →


This guide provides high-level implementation guidance. For detailed API specifications and interactive examples, visit our Storybook documentation.