Pending Review
Pending Review from User Experience (UX)
Toggle Section Component
Overview
The PWC Toggle Section component provides conditional form section display based on checkbox state, enabling dynamic form interfaces where additional fields appear or disappear based on user selections. Built with automatic child element management, accessibility support, and seamless form integration, it creates intuitive progressive disclosure patterns for complex forms requiring conditional input collection.
Core Capabilities
- Conditional Content Display - Automatic show/hide functionality for child elements based on checkbox state with smooth transitions
- Dual Slot Management - Support for default slot (shown when checked) and "false" slot (shown when unchecked) for complete conditional logic
- Child Element State Management - Automatic disabling and enabling of nested form elements based on toggle state and section visibility
- Form Integration - Seamless PWC form context integration with validation, state management, and data synchronization capabilities
- Accessibility Support - ARIA attributes, keyboard navigation, and screen reader compatibility for inclusive conditional form experiences
- Progressive Disclosure Pattern - Clean interface organization that reduces cognitive load while maintaining access to advanced options
When to use Toggle Section:
- Forms requiring conditional input fields where additional options appear based on user preferences or selections
- Settings interfaces with advanced configuration options that should remain hidden until explicitly enabled by users
- Registration and signup flows where optional information collection depends on user choices and preferences
- Configuration panels with feature toggles that reveal additional parameters and customization options when activated
When not to use Toggle Section:
- Simple binary choices where standard checkbox or switch components provide clearer user interaction patterns
- Always-visible form sections where permanent display ensures users don't miss important information or options
- Complex multi-step workflows where wizard or step-by-step navigation provides better user guidance and progress tracking
Basic Implementation
import { PwcButton, PwcForm, PwcInput, PwcToggleSection } from "@progress-i360/pwc-react";
import { useState } from 'react';
function PreferencesForm() {
const [settings, setSettings] = useState({
newsletter: false,
notifications: false
});
return (
<PwcForm>
<PwcToggleSection
label="Newsletter Subscription"
value={settings.newsletter}
onChange={(event) => setSettings((previous) => ({ ...previous, newsletter: event.detail }))}
>
<PwcInput label="Email Address" type="email" required />
</PwcToggleSection>
<PwcToggleSection
label="Push Notifications"
value={settings.notifications}
onChange={(event) => setSettings((previous) => ({ ...previous, notifications: event.detail }))}
>
<PwcInput label="Notification Frequency" type="text" />
</PwcToggleSection>
<PwcButton type="submit" label="Save Preferences" variant="primary" />
</PwcForm>
);
}
import { useEffect, useRef, useState } from 'react';
import '@progress-i360/progress-web-components/button';
import '@progress-i360/progress-web-components/form';
import '@progress-i360/progress-web-components/input';
import '@progress-i360/progress-web-components/toggle-section';
type ToggleSectionElement = HTMLElement & {
value?: boolean;
};
function AdvancedProfileForm() {
const publicProfileRef = useRef<ToggleSectionElement | null>(null);
const notificationsRef = useRef<ToggleSectionElement | null>(null);
const [settings, setSettings] = useState({
publicProfile: false,
notifications: false
});
useEffect(() => {
const section = publicProfileRef.current;
if (!section) {
return;
}
section.value = settings.publicProfile;
const handleChange = (event: Event) => {
const detail = (event as CustomEvent<{ value: boolean }>).detail;
setSettings((previous) => ({ ...previous, publicProfile: detail?.value ?? false }));
};
section.addEventListener('pwc-change', handleChange);
return () => {
section.removeEventListener('pwc-change', handleChange);
};
}, [settings.publicProfile]);
useEffect(() => {
const section = notificationsRef.current;
if (!section) {
return;
}
section.value = settings.notifications;
const handleChange = (event: Event) => {
const detail = (event as CustomEvent<{ value: boolean }>).detail;
setSettings((previous) => ({ ...previous, notifications: detail?.value ?? false }));
};
section.addEventListener('pwc-change', handleChange);
return () => {
section.removeEventListener('pwc-change', handleChange);
};
}, [settings.notifications]);
return (
<pwc-form>
<pwc-toggle-section ref={publicProfileRef} label="Public Profile">
<pwc-input label="Display Name" required></pwc-input>
<pwc-input label="Bio" type="textarea"></pwc-input>
</pwc-toggle-section>
<pwc-toggle-section ref={notificationsRef} label="Email Notifications">
<pwc-input label="Notification Email" type="email"></pwc-input>
</pwc-toggle-section>
<pwc-button type="submit" variant="primary" label="Save Settings"></pwc-button>
</pwc-form>
);
}
// component.ts
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/button";
import "@progress-i360/progress-web-components/checkbox";
import "@progress-i360/progress-web-components/form";
import "@progress-i360/progress-web-components/form-expander";
import "@progress-i360/progress-web-components/form-section";
import "@progress-i360/progress-web-components/input";
import "@progress-i360/progress-web-components/notice";
import "@progress-i360/progress-web-components/radio";
import "@progress-i360/progress-web-components/radio-section";
import "@progress-i360/progress-web-components/select";
import "@progress-i360/progress-web-components/textarea";
import "@progress-i360/progress-web-components/time";
import "@progress-i360/progress-web-components/toggle-section";
@Component({
selector: 'toggle-section-demo',
template: `
<pwc-form heading="Event Registration" subheading="Please complete your registration">
<!-- Basic Information - Always visible -->
<pwc-form-section heading="Basic Information">
<pwc-input
label="Full Name"
[value]="formData.fullName"
[isRequired]="true"
(pwc-change)="updateField('fullName', $event)">
</pwc-input>
<pwc-input
label="Email"
type="email"
[value]="formData.email"
[isRequired]="true"
(pwc-change)="updateField('email', $event)">
</pwc-input>
</pwc-form-section>
<!-- Dietary Restrictions Toggle -->
<pwc-toggle-section
heading="Dietary Restrictions"
subheading="Do you have any dietary requirements?"
[value]="formData.hasDietaryRestrictions"
(pwc-change)="updateField('hasDietaryRestrictions', $event)">
<pwc-textarea
label="Please specify your dietary restrictions"
[value]="formData.dietaryDetails"
placeholder="e.g., vegetarian, gluten-free, allergies..."
rows="3"
(pwc-change)="updateField('dietaryDetails', $event)">
</pwc-textarea>
<pwc-checkbox
label="I have severe allergies that require special attention"
[value]="formData.severeAllergies"
(pwc-change)="updateField('severeAllergies', $event)">
</pwc-checkbox>
</pwc-toggle-section>
<!-- Accommodation Toggle -->
<pwc-toggle-section
heading="Accommodation"
subheading="Do you need hotel accommodation?"
[value]="formData.needsAccommodation"
(pwc-change)="updateField('needsAccommodation', $event)">
<pwc-select
label="Room Type"
[value]="formData.roomType"
[isRequired]="formData.needsAccommodation"
(pwc-change)="updateField('roomType', $event)">
<option value="">Select Room Type</option>
<option value="single">Single Room</option>
<option value="double">Double Room</option>
<option value="suite">Suite</option>
</pwc-select>
<pwc-input
label="Check-in Date"
type="date"
[value]="formData.checkinDate"
[isRequired]="formData.needsAccommodation"
(pwc-change)="updateField('checkinDate', $event)">
</pwc-input>
<pwc-input
label="Check-out Date"
type="date"
[value]="formData.checkoutDate"
[isRequired]="formData.needsAccommodation"
(pwc-change)="updateField('checkoutDate', $event)">
</pwc-input>
<pwc-checkbox
label="I have accessibility requirements"
[value]="formData.accessibilityNeeds"
(pwc-change)="updateField('accessibilityNeeds', $event)">
</pwc-checkbox>
</pwc-toggle-section>
<!-- Transportation Toggle -->
<pwc-toggle-section
heading="Transportation"
subheading="Do you need transportation assistance?"
[value]="formData.needsTransportation"
(pwc-change)="updateField('needsTransportation', $event)">
<pwc-radio-section
heading="Transportation Type"
name="transportationType"
[value]="formData.transportationType"
(pwc-change)="updateField('transportationType', $event)">
<pwc-radio value="airport" label="Airport shuttle"></pwc-radio>
<pwc-radio value="hotel" label="Hotel shuttle"></pwc-radio>
<pwc-radio value="car" label="Rental car assistance"></pwc-radio>
</pwc-radio-section>
<pwc-input
label="Flight Number (if applicable)"
[value]="formData.flightNumber"
placeholder="e.g., UA123"
(pwc-change)="updateField('flightNumber', $event)">
</pwc-input>
<pwc-time
label="Arrival Time"
[value]="formData.arrivalTime"
(pwc-change)="updateField('arrivalTime', $event)">
</pwc-time>
</pwc-toggle-section>
<!-- Additional Services Toggle -->
<pwc-toggle-section
heading="Additional Services"
subheading="Are you interested in additional services?"
[value]="formData.wantsAdditionalServices"
(pwc-change)="updateField('wantsAdditionalServices', $event)">
<pwc-form-expander title="Conference Services">
<pwc-checkbox
label="Professional networking session"
[value]="formData.networking"
(pwc-change)="updateField('networking', $event)">
</pwc-checkbox>
<pwc-checkbox
label="Workshop materials delivery"
[value]="formData.workshopMaterials"
(pwc-change)="updateField('workshopMaterials', $event)">
</pwc-checkbox>
<pwc-checkbox
label="Digital certificate of attendance"
[value]="formData.certificate"
(pwc-change)="updateField('certificate', $event)">
</pwc-checkbox>
</pwc-form-expander>
</pwc-toggle-section>
<!-- Form Actions -->
<pwc-form-section>
<div class="form-actions">
<pwc-button
label="Save Draft"
variant="outline"
(pwc-click)="saveDraft()">
</pwc-button>
<pwc-button
label="Submit Registration"
variant="primary"
[disabled]="!isFormValid()"
(pwc-click)="submitForm()">
</pwc-button>
</div>
</pwc-form-section>
</pwc-form>
<!-- Registration Summary -->
<div class="registration-summary" *ngIf="showSummary">
<pwc-notice
variant="info"
heading="Registration Summary"
[dismissible]="false">
</pwc-notice>
<div class="summary-content">
<p><strong>Name:</strong> {{ formData.fullName }}</p>
<p><strong>Email:</strong> {{ formData.email }}</p>
<p><strong>Dietary Restrictions:</strong> {{ formData.hasDietaryRestrictions ? 'Yes' : 'No' }}</p>
<p><strong>Accommodation:</strong> {{ formData.needsAccommodation ? formData.roomType + ' room' : 'Not needed' }}</p>
<p><strong>Transportation:</strong> {{ formData.needsTransportation ? formData.transportationType : 'Not needed' }}</p>
<p><strong>Additional Services:</strong> {{ formData.wantsAdditionalServices ? getSelectedServicesCount() + ' selected' : 'None' }}</p>
</div>
<pwc-button
label="Edit Registration"
variant="outline"
(pwc-click)="editRegistration()">
</pwc-button>
</div>
`,
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class ToggleSectionDemo {
showSummary = false;
formData = {
// Basic Information
fullName: '',
email: '',
// Dietary Restrictions
hasDietaryRestrictions: false,
dietaryDetails: '',
severeAllergies: false,
// Accommodation
needsAccommodation: false,
roomType: '',
checkinDate: '',
checkoutDate: '',
accessibilityNeeds: false,
// Transportation
needsTransportation: false,
transportationType: '',
flightNumber: '',
arrivalTime: '',
// Additional Services
wantsAdditionalServices: false,
networking: false,
workshopMaterials: false,
certificate: false
};
updateField(fieldName: string, event: CustomEvent<any>) {
const detail = event.detail;
const value = detail && typeof detail === 'object' && 'value' in detail ? detail.value : detail;
(this.formData as any)[fieldName] = value;
// Clear dependent fields when parent toggle is turned off
if (fieldName === 'hasDietaryRestrictions' && !value) {
this.formData.dietaryDetails = '';
this.formData.severeAllergies = false;
}
if (fieldName === 'needsAccommodation' && !value) {
this.formData.roomType = '';
this.formData.checkinDate = '';
this.formData.checkoutDate = '';
this.formData.accessibilityNeeds = false;
}
if (fieldName === 'needsTransportation' && !value) {
this.formData.transportationType = '';
this.formData.flightNumber = '';
this.formData.arrivalTime = '';
}
if (fieldName === 'wantsAdditionalServices' && !value) {
this.formData.networking = false;
this.formData.workshopMaterials = false;
this.formData.certificate = false;
}
}
isFormValid(): boolean {
// Basic validation
if (!this.formData.fullName || !this.formData.email) {
return false;
}
// Conditional validation for accommodation
if (this.formData.needsAccommodation) {
if (!this.formData.roomType || !this.formData.checkinDate || !this.formData.checkoutDate) {
return false;
}
}
return true;
}
getSelectedServicesCount(): number {
let count = 0;
if (this.formData.networking) count++;
if (this.formData.workshopMaterials) count++;
if (this.formData.certificate) count++;
return count;
}
saveDraft() {
console.log('Saving draft registration:', this.formData);
// Simulate save success
alert('Draft saved successfully!');
}
submitForm() {
if (this.isFormValid()) {
console.log('Submitting registration:', this.formData);
this.showSummary = true;
}
}
editRegistration() {
this.showSummary = false;
}
}
import '@progress-i360/progress-web-components/input';
import '@progress-i360/progress-web-components/toggle-section';
const toggleSection = document.createElement('pwc-toggle-section');
toggleSection.label = 'Enable Notifications';
toggleSection.name = 'notifications';
const emailInput = document.createElement('pwc-input');
emailInput.label = 'Email Address';
emailInput.placeholder = 'Enter your email';
emailInput.required = true;
toggleSection.appendChild(emailInput);
toggleSection.addEventListener('pwc-change', (event) => {
const detail = event.detail;
const value = detail && typeof detail === 'object' && 'value' in detail ? detail.value : detail;
console.log('Notifications toggled:', value);
});
document.body.appendChild(toggleSection);
Usage Patterns
- Conditional Form Fields - Additional input fields that appear based on user selections for progressive form disclosure
- Feature Configuration - Settings panels where advanced options are revealed when features are enabled
- Progressive Registration - Multi-step signup processes where optional information collection depends on user choices
- Preference Management - User preference interfaces with nested options that activate based on primary selections
Best Practices
Content Strategy Guidelines
- Clear Toggle Labels - Use descriptive labels that clearly indicate what content will be shown or hidden when toggled
- Logical Content Grouping - Organize conditional content in meaningful groups that match user mental models and workflow expectations
- Appropriate Default States - Set sensible default toggle states that reduce cognitive load and match common user preferences
- Progressive Complexity - Structure conditional content from simple to complex to guide users through configuration workflows naturally
Performance Optimization
- Efficient Child Management - Use optimized DOM manipulation patterns for showing/hiding child elements without excessive re-rendering
- Event Handler Optimization - Implement debounced change handlers and efficient event delegation to manage nested form interactions
- State Synchronization - Maintain consistent state between toggle checkbox and child element visibility with proper lifecycle management
- Form Validation Coordination - Handle validation states appropriately for hidden fields and conditional validation requirements
Integration Architecture
- Form Context Integration - Coordinate seamlessly with PWC form systems for validation, data collection, and state management workflows
- Child Component Communication - Implement proper parent-child communication patterns for nested form element state management
- Accessibility Standards - Ensure proper ARIA attributes, focus management, and screen reader announcements for conditional content changes
- Data Model Coordination - Design data structures that appropriately handle conditional fields and nested form data relationships
Common Use Cases
Data Table Headers
- Configuration tables with advanced settings that appear when features are enabled through toggle sections
- User permission matrices where additional role options are revealed based on access level selections
- Data export configurations with format-specific options that appear based on selected export types
Search Result Sections
- Advanced search filters that expand to show detailed criteria when filter categories are enabled
- Search result customization options with display preferences that activate based on view type selections
- Saved search configurations with notification settings that appear when search alerts are enabled
Dashboard Widget Headers
- Widget configuration panels with advanced styling options that appear when customization is enabled
- Dashboard layout settings with grid options that are revealed when custom layout mode is activated
- Performance monitoring controls with detailed metrics that appear when advanced monitoring is enabled
Troubleshooting
Common Issues
Actions Not Triggering
Symptoms: Toggle doesn't show/hide children, checkbox state doesn't update, or change events don't fire properly
Solutions:
-
Verify that child element slot assignments work correctly and elements are properly nested within toggle section
-
Check that checkbox change handlers are properly bound and component instance references are maintained correctly
-
Ensure that form context integration handles conditional field states appropriately with proper validation coordination
Actions Not Visible
Symptoms: Child elements don't appear when toggled, slots don't render content, or conditional sections remain hidden
Solutions:
-
Confirm that slot element targeting works correctly for both default and "false" slots with proper DOM queries
-
Check that child element display styles are managed properly with visibility and disabled state coordination
-
Verify that component rendering handles slot content properly and nested form elements receive appropriate styling
Layout Issues
Symptoms: Conditional content appears with layout problems, child elements overlap, or spacing is inconsistent
Solutions:
-
Use appropriate flex layout patterns and gap spacing to ensure consistent visual hierarchy when content appears
-
Check that child element styling accommodates show/hide transitions without disrupting overall form layout
-
Ensure that responsive design patterns work correctly when conditional content changes form dimensions and structure
Icon Problems
Symptoms: Checkbox icons don't display properly, toggle states don't show visual feedback, or icon theming is inconsistent
Solutions:
-
Verify that checkbox component icons render correctly within toggle section context with appropriate color theming
-
Check that disabled state styling applies consistently to both toggle checkbox and nested child elements
-
Ensure that focus states provide clear visual feedback for keyboard navigation and accessibility requirements
Implementation Support
- Conditional Logic Patterns - Best practices for designing intuitive conditional form workflows with appropriate progressive disclosure
- Child Component Management - Comprehensive guidance for nested form element coordination and state synchronization strategies
- Accessibility Implementation - WCAG guidelines for conditional content, focus management, and screen reader optimization patterns
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.