Pending Review
Pending Review from User Experience (UX)
Switch Component
Overview
The PWC Switch component provides an interactive toggle control for binary state management with enhanced visual feedback and form integration. Built on the InputBase foundation with integrated icon system and label container architecture, it offers smooth state transitions, accessibility compliance, and seamless PWC form system integration for preference management and feature toggling workflows.
Core Capabilities
- Visual State Indicators - Integrated checkmark and close icons with color-coded backgrounds for clear on/off state communication
- Interactive Thumb Animation - Smooth sliding thumb animation with radio-button icon that provides immediate visual feedback during state changes
- Label Container Integration - Built-in label container system supporting hints, headings, and required field indicators for comprehensive form integration
- Form Validation Support - Boolean value validation with required field checking and error message display for form integrity
- Loading State Management - Skeleton rendering during form loading with consistent visual feedback and progressive enhancement
- Accessibility Compliance - Full keyboard navigation, screen reader support, and semantic HTML structure for inclusive user interaction
When to use Switch:
- Binary preference toggles requiring immediate visual feedback and clear on/off state representation for user settings
- Feature enablement controls where users need to activate or deactivate functionality with obvious state indication
- Settings panels with binary configuration options that benefit from toggle-style interaction over checkbox presentation
- Dashboard controls where switch styling provides better visual hierarchy and user experience than traditional checkboxes
When not to use Switch:
- Multi-option selections where radio buttons or select dropdowns provide more appropriate choice mechanisms
- Agreement or consent scenarios where checkbox semantics provide clearer legal and user experience implications
- Form fields requiring explicit user acknowledgment where checkbox interaction patterns offer better compliance tracking
Basic Implementation
import { PwcSwitch } from "@progress-i360/pwc-react";
import { useState } from 'react';
function UserPreferences() {
const [preferences, setPreferences] = useState({
notifications: true,
darkMode: false
});
const updatePreference = (field: string, value: boolean) => {
setPreferences((previous) => ({ ...previous, [field]: value }));
};
return (
<>
<PwcSwitch
name="notifications"
label="Enable Notifications"
hint="Receive updates about your account and activity"
value={preferences.notifications}
required
autoFocus
onChange={(event) => updatePreference('notifications', event.detail)}
/>
<PwcSwitch
name="darkMode"
label="Dark Mode"
hint="Use dark theme for better viewing in low light"
value={preferences.darkMode}
onChange={(event) => updatePreference('darkMode', event.detail)}
/>
</>
);
}
import { useEffect, useMemo, useRef, useState } from 'react';
import '@progress-i360/progress-web-components/button';
import '@progress-i360/progress-web-components/form';
import '@progress-i360/progress-web-components/switch';
type SwitchElement = HTMLElement & {
checked?: boolean;
disabled?: boolean;
required?: boolean;
};
type ButtonElement = HTMLElement & {
label?: string;
disabled?: boolean;
variant?: string;
};
type PwcSubmitDetail = {
payload: Record<string, unknown>;
success: () => void;
};
function ApplicationSettingsForm() {
const formRef = useRef<HTMLElement | null>(null);
const maintenanceSwitchRef = useRef<SwitchElement | null>(null);
const cachingSwitchRef = useRef<SwitchElement | null>(null);
const submitButtonRef = useRef<ButtonElement | null>(null);
const initialSettings = useMemo(() => ({ maintenance: false, caching: true }), []);
const [settings, setSettings] = useState(initialSettings);
const [isSubmitting, setIsSubmitting] = useState(false);
const [hasChanges, setHasChanges] = useState(false);
useEffect(() => {
const changed =
settings.maintenance !== initialSettings.maintenance || settings.caching !== initialSettings.caching;
setHasChanges(changed);
}, [initialSettings, settings]);
useEffect(() => {
const maintenanceSwitch = maintenanceSwitchRef.current;
if (!maintenanceSwitch) {
return;
}
maintenanceSwitch.checked = settings.maintenance;
maintenanceSwitch.disabled = isSubmitting;
const handleMaintenanceChange = (event: Event) => {
const detail = (event as CustomEvent<boolean>).detail;
setSettings((previous) => {
const next = { ...previous, maintenance: detail };
return detail ? { ...next, caching: false } : next;
});
};
maintenanceSwitch.addEventListener('pwc-change', handleMaintenanceChange);
return () => {
maintenanceSwitch.removeEventListener('pwc-change', handleMaintenanceChange);
};
}, [isSubmitting, settings.maintenance]);
useEffect(() => {
const cachingSwitch = cachingSwitchRef.current;
if (!cachingSwitch) {
return;
}
cachingSwitch.checked = settings.caching;
cachingSwitch.disabled = isSubmitting || settings.maintenance;
const handleCachingChange = (event: Event) => {
const detail = (event as CustomEvent<boolean>).detail;
setSettings((previous) => ({ ...previous, caching: detail }));
};
cachingSwitch.addEventListener('pwc-change', handleCachingChange);
return () => {
cachingSwitch.removeEventListener('pwc-change', handleCachingChange);
};
}, [isSubmitting, settings.caching, settings.maintenance]);
useEffect(() => {
const button = submitButtonRef.current;
if (!button) {
return;
}
button.label = isSubmitting ? 'Applying...' : 'Apply Changes';
button.disabled = !hasChanges || isSubmitting;
button.variant = 'primary';
}, [hasChanges, isSubmitting]);
useEffect(() => {
const formElement = formRef.current;
if (!formElement) {
return;
}
const handleSubmit = (event: Event) => {
const submitDetail = (event as CustomEvent<PwcSubmitDetail>).detail;
if (!submitDetail || isSubmitting) {
return;
}
setIsSubmitting(true);
setTimeout(() => {
submitDetail.success();
setIsSubmitting(false);
setHasChanges(false);
}, 2000);
};
formElement.addEventListener('pwc-submit', handleSubmit as EventListener);
return () => {
formElement.removeEventListener('pwc-submit', handleSubmit as EventListener);
};
}, [isSubmitting]);
return (
<pwc-form ref={formRef}>
<pwc-switch
ref={maintenanceSwitchRef}
name="maintenance"
label="Maintenance Mode"
hint="Enable maintenance mode (disables caching automatically)"
></pwc-switch>
<pwc-switch
ref={cachingSwitchRef}
name="caching"
label="Application Caching"
hint="Enable caching for improved performance"
></pwc-switch>
<pwc-button
ref={submitButtonRef}
type="submit"
style={{ marginTop: '16px' }}
></pwc-button>
</pwc-form>
);
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/switch";
@Component({
selector: 'switch-demo',
template: `
<pwc-switch
label="Dark Mode"
name="darkMode"
[value]="preferences.darkMode"
hint="Switch between light and dark themes"
(pwc-change)="toggleDarkMode($event)">
</pwc-switch>
<pwc-switch
label="Email Notifications"
name="emailNotifications"
[value]="preferences.emailNotifications"
required
hint="Receive important account updates via email"
(pwc-change)="toggleEmailNotifications($event)">
</pwc-switch>
<pwc-switch
label="Push Notifications"
name="pushNotifications"
[value]="preferences.pushNotifications"
[disabled]="!preferences.emailNotifications"
hint="Browser notifications for real-time updates"
(pwc-change)="togglePushNotifications($event)">
</pwc-switch>
<pwc-switch
label="Auto-save"
name="autoSave"
[value]="preferences.autoSave"
hint="Automatically save changes as you work"
(pwc-change)="toggleAutoSave($event)">
</pwc-switch>
<pwc-switch
label="Beta Features"
name="betaFeatures"
[value]="preferences.betaFeatures"
hint="Access experimental features (may be unstable)"
(pwc-change)="toggleBetaFeatures($event)">
</pwc-switch>
<div class="preferences-summary" *ngIf="hasActivePreferences">
<p>Active features: {{ getActiveFeatures().join(', ') }}</p>
<p>Settings saved: {{ settingsSaved ? 'Yes' : 'Pending...' }}</p>
</div>
`,
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class SwitchDemo {
preferences = {
darkMode: false,
emailNotifications: true,
pushNotifications: false,
autoSave: true,
betaFeatures: false
};
settingsSaved = true;
get hasActivePreferences() {
return Object.values(this.preferences).some(value => value);
}
toggleDarkMode(event: CustomEvent<boolean>) {
this.preferences.darkMode = event.detail;
this.saveSettings();
}
toggleEmailNotifications(event: CustomEvent<boolean>) {
this.preferences.emailNotifications = event.detail;
// Disable push notifications if email is disabled
if (!event.detail) {
this.preferences.pushNotifications = false;
}
this.saveSettings();
}
togglePushNotifications(event: CustomEvent<boolean>) {
this.preferences.pushNotifications = event.detail;
this.saveSettings();
}
toggleAutoSave(event: CustomEvent<boolean>) {
this.preferences.autoSave = event.detail;
this.saveSettings();
}
toggleBetaFeatures(event: CustomEvent<boolean>) {
this.preferences.betaFeatures = event.detail;
this.saveSettings();
}
getActiveFeatures(): string[] {
const features = [];
if (this.preferences.darkMode) features.push('Dark Mode');
if (this.preferences.emailNotifications) features.push('Email Notifications');
if (this.preferences.pushNotifications) features.push('Push Notifications');
if (this.preferences.autoSave) features.push('Auto-save');
if (this.preferences.betaFeatures) features.push('Beta Features');
return features;
}
private saveSettings() {
this.settingsSaved = false;
// Simulate API call
setTimeout(() => {
this.settingsSaved = true;
console.log('Settings saved:', this.preferences);
}, 500);
}
}
import '@progress-i360/progress-web-components/switch';
// Create toggle switch for notification preferences
const notificationSwitch = document.createElement('pwc-switch');
notificationSwitch.label = 'Enable Notifications';
notificationSwitch.name = 'notifications';
notificationSwitch.checked = false;
notificationSwitch.addEventListener('pwc-change', (event) => {
const isEnabled = event.detail;
console.log('Notifications:', isEnabled ? 'enabled' : 'disabled');
});
document.body.appendChild(notificationSwitch);
Usage Patterns
- User Preference Toggles - Settings panels with binary preferences for themes, notifications, and feature enablement
- Feature Control Switches - Dashboard and configuration interfaces where features can be activated or deactivated
- Privacy and Security Settings - User control panels for privacy preferences, tracking consent, and security features
- System Configuration Toggles - Administrative interfaces for system-level feature management and operational controls
Best Practices
Content Strategy Guidelines
- Clear Binary Labels - Use descriptive labels that clearly communicate the on/off state and functionality being controlled
- Informative Hint Text - Provide context about what the switch controls and the impact of enabling or disabling the feature
- Consistent State Communication - Ensure visual feedback clearly indicates current state with appropriate color coding and iconography
- Logical Grouping - Organize related switches into sections with clear headings for better user comprehension and navigation
Performance Optimization
- Efficient State Management - Optimize boolean state updates and form synchronization for smooth user interactions
- Icon Loading Strategy - Ensure checkmark, close, and radio-button icons are properly loaded and cached for consistent visual feedback
- Animation Performance - Implement smooth thumb transitions and state changes without impacting overall application performance
- Loading State Integration - Properly handle skeleton rendering during form initialization and switch component loading
Integration Architecture
- Form Context Coordination - Integrate seamlessly with PWC form systems for validation, submission, and error handling workflows
- Label Container Integration - Leverage label container architecture for consistent styling, hint display, and required field indicators
- Accessibility Standards - Ensure proper ARIA attributes, keyboard navigation, and screen reader compatibility for switch interactions
- Design Token Usage - Leverage PWC design tokens for consistent styling, spacing, and color usage across switch components
Common Use Cases
Data Table Headers
- Column visibility toggles with switches for showing or hiding specific data columns and table features
- Real-time update switches for enabling live data refresh and automatic table updates
- Export feature toggles for controlling data export options and formatting preferences
Search Result Sections
- Filter activation switches for enabling or disabling specific search filters and refinement options
- View mode toggles for switching between different result presentation styles and layouts
- Auto-complete switches for controlling search suggestion behavior and user assistance features
Dashboard Widget Headers
- Widget activation switches for enabling or disabling specific dashboard components and data displays
- Auto-refresh toggles for controlling automatic data updates and real-time synchronization
- Notification switches for managing widget-specific alerts and status updates
Troubleshooting
Common Issues
Actions Not Triggering
Symptoms: Switch doesn't toggle states, change events don't fire, or value updates don't register properly
Solutions:
-
Verify that input element is properly connected and change/input event handlers are correctly bound to functional callbacks
-
Check that disabled state doesn't prevent legitimate user interactions or interfere with switch toggling mechanism
-
Ensure form context integration doesn't block switch state updates or prevent proper value synchronization
Actions Not Visible
Symptoms: Switch doesn't render correctly, icons don't appear, or visual states don't update properly
Solutions:
-
Confirm that checkmark, close, and radio-button icons are loaded and available in your icon system configuration
-
Check that switch styling renders correctly with proper background colors, thumb positioning, and state transitions
-
Verify that label container integration displays properly with appropriate spacing, alignment, and visual hierarchy
Layout Issues
Symptoms: Switch appears with incorrect spacing, alignment, or positioning within form layouts and containers
Solutions:
-
Use appropriate container styling to accommodate switch component dimensions and interactive area requirements
-
Check that label container layout works correctly with switch positioning and provides adequate spacing for touch targets
-
Ensure responsive design patterns accommodate switch components across different screen sizes and device orientations
Icon Problems
Symptoms: Switch icons don't display correctly, appear with wrong colors, or don't update based on state changes
Solutions:
-
Verify that icon color theming works correctly for normal, disabled, and checked states with appropriate contrast ratios
-
Check that icon sizing is appropriate for switch dimensions and provides clear visual communication of state
-
Ensure icon transitions and state changes function smoothly during switch interactions and value updates
Implementation Support
- State Management Patterns - Best practices for handling boolean values, form integration, and switch group coordination
- Accessibility Compliance - WCAG guidelines implementation, keyboard navigation patterns, and screen reader optimization for switch controls
- Visual Design Integration - Switch styling strategies, icon usage patterns, and consistent visual feedback for different application contexts
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.