Skip to content

Pending Review

Pending Review from User Experience (UX)

Label Container Component

Overview

The PWC Label Container component provides a wrapper for form inputs that includes integrated labeling, hint support, and interactive styling. Built as a utility function, it creates a cohesive label-input relationship with proper cursor handling, disabled states, and hover effects for enhanced user experience.

Core Capabilities

  • Integrated Label-Input Wrapper - Combines form inputs with labels in a single interactive container for improved usability
  • Required Field Indicators - Visual asterisk markers with semantic red color coding to clearly identify mandatory fields
  • Hint System Integration - Built-in support for contextual hints and headings that provide user guidance and field explanations
  • Interactive States - Comprehensive hover and active state styling for both checked and unchecked input states
  • Disabled State Management - Proper cursor and interaction handling when form inputs are disabled or readonly
  • Slot-Based Architecture - Flexible content insertion through renderSlot function for various input types and layouts

When to use Label Container:

  • Checkbox and radio button inputs requiring integrated label-input interaction for better user experience
  • Form fields needing cohesive styling between labels and interactive elements
  • Inputs with contextual hints that should be visually connected to both label and input
  • Custom form controls requiring consistent label container behavior and styling

When not to use Label Container:

  • Standard text inputs where separate label and input elements provide better semantic structure
  • Complex form layouts where label positioning needs custom control and flexibility
  • Read-only display content that doesn't require interactive label container behavior

Basic Implementation

import React from 'react';
import { PwcCheckbox, PwcRadio, PwcRadioSection } from "@progress-i360/pwc-react";

function MyComponent() {
  const handleTermsChange = (event) => {
    console.log('Terms accepted:', event.target.checked);
  };

  return (
    <>
      <PwcCheckbox
        name="terms"
        label="I accept the terms and conditions"
        required
        hint="Please review our terms before proceeding"
        onChange={handleTermsChange}
      />

      <PwcCheckbox
        name="newsletter"
        label="Subscribe to newsletter"
        hint="Receive product updates and special offers"
      />

      <PwcRadioSection heading="Theme">
        <PwcRadio name="theme" label="Light" value="light" defaultChecked />
        <PwcRadio name="theme" label="Dark" value="dark" />
      </PwcRadioSection>
    </>
  );
}
import { useEffect, useRef, useState } from 'react';
import '@progress-i360/progress-web-components/checkbox';
import '@progress-i360/progress-web-components/radio';
import '@progress-i360/progress-web-components/radio-section';
import '@progress-i360/progress-web-components/switch';

type ToggleElement = HTMLElement & { checked?: boolean };

function PreferenceLabels() {
  const newsletterRef = useRef<ToggleElement | null>(null);
  const notificationsRef = useRef<ToggleElement | null>(null);
  const lightThemeRef = useRef<ToggleElement | null>(null);
  const darkThemeRef = useRef<ToggleElement | null>(null);

  const [state, setState] = useState({
    newsletter: false,
    notifications: true,
    theme: 'light'
  });

  useEffect(() => {
    const newsletterEl = newsletterRef.current;
    const notificationsEl = notificationsRef.current;
    const lightThemeEl = lightThemeRef.current;
    const darkThemeEl = darkThemeRef.current;

    if (!newsletterEl || !notificationsEl || !lightThemeEl || !darkThemeEl) {
      return;
    }

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

    const handleNotifications = (event: Event) => {
      const detail = (event as CustomEvent<boolean>).detail;
      setState((prev) => ({ ...prev, notifications: detail }));
    };

    const handleTheme = (event: Event) => {
      const detail = (event as CustomEvent<string>).detail;
      setState((prev) => ({ ...prev, theme: detail }));
    };

    newsletterEl.addEventListener('pwc-change', handleNewsletter);
    notificationsEl.addEventListener('pwc-change', handleNotifications);
    lightThemeEl.addEventListener('pwc-change', handleTheme);
    darkThemeEl.addEventListener('pwc-change', handleTheme);

    return () => {
      newsletterEl.removeEventListener('pwc-change', handleNewsletter);
      notificationsEl.removeEventListener('pwc-change', handleNotifications);
      lightThemeEl.removeEventListener('pwc-change', handleTheme);
      darkThemeEl.removeEventListener('pwc-change', handleTheme);
    };
  }, []);

  useEffect(() => {
    if (newsletterRef.current) {
      newsletterRef.current.checked = state.newsletter;
    }
    if (notificationsRef.current) {
      notificationsRef.current.checked = state.notifications;
    }
    if (lightThemeRef.current) {
      lightThemeRef.current.checked = state.theme === 'light';
    }
    if (darkThemeRef.current) {
      darkThemeRef.current.checked = state.theme === 'dark';
    }
  }, [state]);

  return (
    <>
      <pwc-checkbox
        ref={newsletterRef}
        name="newsletter"
        label="Subscribe to newsletter"
        hint="Receive product updates and special offers"
      ></pwc-checkbox>

      <pwc-switch
        ref={notificationsRef}
        name="notifications"
        label="Enable push notifications"
        hint="Get notified about important account activity"
      ></pwc-switch>

      <pwc-radio-section heading="Theme Preference">
        <pwc-radio
          ref={lightThemeRef}
          name="theme"
          value="light"
          label="Light Theme"
        ></pwc-radio>
        <pwc-radio
          ref={darkThemeRef}
          name="theme"
          value="dark"
          label="Dark Theme"
        ></pwc-radio>
      </pwc-radio-section>
    </>
  );
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/checkbox";
import "@progress-i360/progress-web-components/radio";

@Component({
  selector: 'label-container-demo',
  template: `
    <div class="preferences-form">
      <pwc-checkbox 
        name="emailNotifications" 
        label="Email Notifications" 
        hint="Receive updates about your account"
        hint-heading="Communication Preferences"
        [checked]="preferences.email"
        (pwc-change)="updatePreference('email', $event)">
      </pwc-checkbox>

      <pwc-checkbox 
        name="smsNotifications" 
        label="SMS Notifications" 
        required
        hint="Required for security alerts"
        [checked]="preferences.sms"
        [disabled]="!preferences.email"
        (pwc-change)="updatePreference('sms', $event)">
      </pwc-checkbox>

      <pwc-radio 
        name="theme" 
        label="Light Theme" 
        value="light"
        [checked]="selectedTheme === 'light'"
        (pwc-change)="selectTheme('light')">
      </pwc-radio>

      <pwc-radio 
        name="theme" 
        label="Dark Theme" 
        value="dark"
        [checked]="selectedTheme === 'dark'"
        (pwc-change)="selectTheme('dark')">
      </pwc-radio>
    </div>

    <div class="summary" *ngIf="hasPreferences">
      <p>Active preferences: {{ getActivePreferences() }}</p>
    </div>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class LabelContainerDemo {
  preferences = { email: false, sms: false };
  selectedTheme = 'light';

  get hasPreferences() {
    return this.preferences.email || this.preferences.sms;
  }

  updatePreference(type: 'email' | 'sms', event: any) {
    this.preferences[type] = event.detail;

    // Disable SMS if email is disabled
    if (type === 'email' && !event.detail) {
      this.preferences.sms = false;
    }
  }

  selectTheme(theme: string) {
    this.selectedTheme = theme;
  }

  getActivePreferences() {
    const active = [];
    if (this.preferences.email) active.push('Email');
    if (this.preferences.sms) active.push('SMS');
    active.push(`${this.selectedTheme} theme`);
    return active.join(', ');
  }
}
import '@progress-i360/progress-web-components/checkbox';
import '@progress-i360/progress-web-components/radio';
import '@progress-i360/progress-web-components/radio-section';
import '@progress-i360/progress-web-components/switch';

const preferencesForm = document.createElement('div');
preferencesForm.className = 'preferences-form';
preferencesForm.style.display = 'flex';
preferencesForm.style.flexDirection = 'column';
preferencesForm.style.gap = '16px';

const newsletter = document.createElement('pwc-checkbox');
newsletter.setAttribute('name', 'newsletter');
newsletter.setAttribute('label', 'Subscribe to newsletter');
newsletter.setAttribute('hint', 'Get product updates and offers');

const notifications = document.createElement('pwc-switch');
notifications.setAttribute('name', 'notifications');
notifications.setAttribute('label', 'Enable push notifications');

const themeSection = document.createElement('pwc-radio-section');
themeSection.setAttribute('heading', 'Theme Preference');

const light = document.createElement('pwc-radio');
light.setAttribute('name', 'theme');
light.setAttribute('value', 'light');
light.setAttribute('label', 'Light Theme');
light.setAttribute('checked', 'true');

const dark = document.createElement('pwc-radio');
dark.setAttribute('name', 'theme');
dark.setAttribute('value', 'dark');
dark.setAttribute('label', 'Dark Theme');

themeSection.append(light, dark);
preferencesForm.append(newsletter, notifications, themeSection);

document.body.appendChild(preferencesForm);

Usage Patterns

  • Checkbox Integration - Wrap checkbox inputs with labels and hints for enhanced clickable area and user guidance
  • Radio Button Groups - Create cohesive radio button selections with integrated labeling and contextual information
  • Toggle Options - Build preference and settings interfaces with consistent label-input relationships
  • Custom Input Wrapping - Provide unified styling and behavior for custom form controls and specialized inputs

Best Practices

Content Strategy Guidelines

  • Clear Label Text - Use descriptive, actionable language that clearly explains what the input controls or affects
  • Helpful Hint Content - Provide contextual guidance that helps users understand the impact and purpose of options
  • Consistent Interaction Patterns - Maintain uniform behavior across similar input types and preference categories
  • Appropriate Required Indicators - Use required markers judiciously for inputs that are truly mandatory for functionality

Performance Optimization

  • Efficient Slot Rendering - Design renderSlot functions to minimize re-renders and optimize template creation
  • State Management Optimization - Structure component state to prevent unnecessary label container updates during interactions
  • Conditional Hint Rendering - Only render hint components when hint content is provided to reduce DOM complexity
  • Event Handling Efficiency - Use appropriate event delegation and handling patterns for multiple label containers

Integration Architecture

  • Semantic HTML Structure - Ensure proper label-input association and accessibility through semantic markup
  • Design System Integration - Leverage typography and color tokens for consistent visual presentation
  • Form Context Coordination - Integrate with form validation and submission systems for complete user experience
  • Responsive Design - Consider label container behavior across different screen sizes and interaction methods

Common Use Cases

Preference Interfaces

  • User account settings with privacy, notification, and display preference toggles
  • Application configuration options with feature enablement and customization controls
  • Accessibility settings with contrast, font size, and interaction preference options

Form Input Enhancement

  • Checkbox and radio button groups with improved clickable areas and visual hierarchy
  • Terms and conditions acceptance with integrated legal text and requirement indicators
  • Survey and feedback forms with clear option labeling and contextual guidance

Settings Management

  • System configuration interfaces with service enablement and parameter controls
  • User profile customization with visibility, contact, and social sharing preferences
  • Integration settings with third-party service connections and permission management

Troubleshooting

Common Issues

Actions Not Triggering

Symptoms: Clicking label containers doesn't activate associated input elements or trigger change events

Solutions:'

  • Verify renderSlot function returns properly structured input elements with event handlers

  • Check that input elements are not prevented from receiving events by CSS pointer-events or disabled states

  • Ensure label container styling doesn't interfere with input element accessibility

Actions Not Visible

Symptoms: Label containers don't render or appear with missing content or styling

Solutions:

  • Confirm label property contains descriptive text content for rendering

  • Check that hint and hintHeading content renders correctly when provided

  • Verify required indicator asterisks appear when required property is set to true

Layout Issues

Symptoms: Label containers appear misaligned or with incorrect spacing between label text and input elements

Solutions:

  • Use appropriate gap and padding values from design system spacing tokens

  • Check parent container styling doesn't conflict with label container flex layout

  • Ensure consistent alignment across different input types within the same form or section

Icon Problems

Symptoms: Required asterisks, hint icons, or input state indicators don't display with correct colors or positioning

Solutions:

  • Verify design system color tokens are loaded for red-base asterisk coloring

  • Check that hint component icons render correctly when hint content is provided

  • Ensure input state styling (hover, active, checked) works properly with container CSS

Implementation Support

  • Accessibility Integration - Guidance for proper label-input association, keyboard navigation, and screen reader compatibility
  • Form Architecture - Best practices for integrating label containers with validation systems and form submission workflows
  • Design System Consistency - Token usage patterns for typography, spacing, and interactive state styling

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.