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.