Skip to content

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.