Pending Review
Pending Review from User Experience (UX)
Button Group Component
Overview
The PWC Button Group component provides a single-selection interface using connected buttons for mutually exclusive options. Built with Lit web components, it integrates seamlessly with form validation and offers visual feedback for selected states.
Core Capabilities
-
Single Selection - Exclusive selection pattern where only one option can be active at a time
-
Visual Connectivity - Connected button styling with shared borders and rounded corners on ends
-
Form Integration - Native form field behavior with validation, required state, and loading skeleton support
-
Accessibility Focus - Full keyboard navigation with proper ARIA attributes and screen reader compatibility
-
Option Management - Flexible option configuration with labels, values, and individual disabled states
-
State Indication - Clear visual feedback with checkmark icons and background highlighting for selected options
When to use Button Group:
-
Single-choice selections where all options should be visible simultaneously
-
Filter controls and view mode toggles with 2-5 related options
-
Category selection and content type switching interfaces
-
Form inputs requiring exclusive choice from a predefined set
When not to use Button Group:
-
Multiple selection scenarios where users need to choose several options
-
Long lists of options that would create excessive horizontal space requirements
-
Navigation between different pages or sections where other navigation patterns are more appropriate
Basic Implementation
import React from 'react';
import { PwcButtonGroup } from "@progress-i360/pwc-react";
function MyComponent() {
const viewOptions = [
{ label: 'List', value: 'list' },
{ label: 'Grid', value: 'grid' },
{ label: 'Card', value: 'card' }
];
return (
<PwcButtonGroup
label="View Mode"
name="viewMode"
options={viewOptions}
required
/>
);
}
import { useEffect, useMemo, useRef, useState } from 'react';
import '@progress-i360/progress-web-components/button-group';
type GroupOption = { label: string; value: string };
function PrioritySelector() {
const options = useMemo<GroupOption[]>(() => [
{ label: 'Low', value: 'low' },
{ label: 'Medium', value: 'medium' },
{ label: 'High', value: 'high' }
], []);
const groupRef = useRef<(HTMLElement & { options?: GroupOption[]; value?: string }) | null>(null);
const [selected, setSelected] = useState('medium');
useEffect(() => {
if (groupRef.current) {
groupRef.current.options = options;
}
}, [options]);
useEffect(() => {
const element = groupRef.current;
if (!element) {
return;
}
const handleChange = (event: Event) => {
const { detail } = event as CustomEvent<string>;
setSelected(detail);
};
element.addEventListener('pwc-change', handleChange as EventListener);
return () => {
element.removeEventListener('pwc-change', handleChange as EventListener);
};
}, []);
useEffect(() => {
if (groupRef.current) {
groupRef.current.value = selected;
}
}, [selected]);
return (
<div style={{ maxWidth: '320px' }}>
<pwc-button-group
ref={groupRef}
label="Priority Level"
name="priority"
hint="Select task priority"
required="true"
></pwc-button-group>
</div>
);
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/button-group";
import "@progress-i360/progress-web-components/button";
import "@progress-i360/progress-web-components/flex";
import "@progress-i360/progress-web-components/heading";
import "@progress-i360/progress-web-components/body";
@Component({
selector: 'button-group-demo',
template: `
<pwc-flex direction="column" gap="m" padding="m">
<pwc-heading content="View Selection Demo" size="l"></pwc-heading>
<pwc-button-group
label="Display Mode"
[options]="viewOptions"
[value]="selectedView"
(pwc-change)="handleViewChange($event)">
</pwc-button-group>
<pwc-button-group
label="Priority Filter"
[options]="priorityOptions"
[value]="selectedPriority"
[required]="true"
(pwc-change)="handlePriorityChange($event)">
</pwc-button-group>
<pwc-flex gap="s">
<pwc-button label="Add Option" variant="outline" (pwc-click)="addOption()"></pwc-button>
<pwc-button label="Reset Selection" variant="clear" (pwc-click)="resetSelections()"></pwc-button>
</pwc-flex>
<pwc-body [content]="'View: ' + selectedView + ', Priority: ' + (selectedPriority || 'None')" color="subtle" size="xs"></pwc-body>
</pwc-flex>
`,
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class ButtonGroupDemo {
selectedView = 'grid';
selectedPriority = '';
viewOptions = [
{ label: 'List', value: 'list' },
{ label: 'Grid', value: 'grid' },
{ label: 'Card', value: 'card' }
];
priorityOptions = [
{ label: 'High', value: 'high' },
{ label: 'Medium', value: 'medium' },
{ label: 'Low', value: 'low' }
];
handleViewChange(e: Event) {
const ce = (e as CustomEvent);
this.selectedView = ce.detail;
}
handlePriorityChange(e: Event) {
const ce = (e as CustomEvent);
this.selectedPriority = ce.detail;
}
addOption() {
const newOption = { label: 'Table', value: 'table' };
if (!this.viewOptions.find(opt => opt.value === 'table')) {
this.viewOptions = [...this.viewOptions, newOption];
}
}
resetSelections() {
this.selectedView = 'list';
this.selectedPriority = '';
}
}
import '@progress-i360/progress-web-components/button-group';
const buttonGroup = document.createElement('pwc-button-group');
buttonGroup.setAttribute('label', 'View Mode');
buttonGroup.options = [
{ label: 'List', value: 'list' },
{ label: 'Grid', value: 'grid' },
{ label: 'Card', value: 'card' }
];
buttonGroup.addEventListener('pwc-change', (event) => {
console.log('Selected value:', event.detail);
});
document.body.appendChild(buttonGroup);
Usage Patterns
-
View Controls - Toggle between different data visualization modes like list, grid, or card layouts
-
Filter Categories - Single-selection filters for status, type, or priority categories with immediate visual feedback
-
Form Choices - Exclusive selection inputs for preferences, settings, or configuration options in forms
-
Content Switches - Switch between related content types or display modes within the same interface context
Best Practices
Content Strategy Guidelines
-
Clear Labels - Use concise, descriptive labels that clearly differentiate between options
-
Logical Grouping - Organize options in a logical order such as priority levels or chronological sequence
-
Consistent Terminology - Maintain consistent naming conventions across similar button groups
-
Appropriate Scope - Limit to 2-5 options to prevent interface clutter and maintain usability
Performance Optimization
-
Option Caching - Cache option arrays to prevent unnecessary re-renders on component updates
-
Event Debouncing - Implement debouncing for rapid selection changes to reduce processing overhead
-
Conditional Rendering - Only render button groups when options are available and relevant
-
State Management - Use efficient state management patterns to handle selection changes
Integration Architecture
-
Form Context - Leverage form integration for validation, loading states, and submission handling
-
Accessibility Standards - Ensure proper keyboard navigation and screen reader announcements
-
Design Tokens - Use consistent spacing, colors, and typography from the design system
-
Component Composition - Combine with labels, hints, and validation messages for complete form fields
Common Use Cases
Data Filtering
-
Status filters for active, inactive, or pending items in data tables
-
Category filters for content types, departments, or classification systems
-
Time period selections for reports, analytics, and historical data views
Interface Controls
-
View mode toggles for switching between different data presentation formats
-
Theme or appearance selections for user interface customization
-
Language or locale selection for internationalization support
Form Selections
-
Priority level selection for tasks, tickets, or project items
-
Preference settings for notifications, privacy, or display options
-
Configuration choices for features, modules, or application behavior
Troubleshooting
Common Issues
Actions Not Triggering
Symptoms: Button group selections don't fire change events or update values
Solutions:
-
Verify pwc-change event listeners are properly attached
-
Check if button group is disabled or in loading state
-
Ensure options array is properly formatted with value and label properties
Actions Not Visible
Symptoms: Button group doesn't render or appears empty
Solutions:
-
Confirm options array is populated with valid option objects
-
Check CSS display properties and container overflow settings
-
Verify component is imported and registered correctly in the application
Layout Issues
Symptoms: Buttons appear disconnected or with incorrect spacing
Solutions:
-
Check parent container width and flex properties affecting button sizing
-
Ensure proper CSS border-radius and margin styles are not overridden
-
Verify button group is not wrapped in containers with conflicting styling
Icon Problems
Symptoms: Selected state checkmark icons don't appear or display incorrectly
Solutions:
-
Confirm icon system is properly loaded and available
-
Check color token values for disabled and normal icon states
-
Verify selected state styling is properly applied with background colors
Implementation Support
-
Form Integration - Pattern guidance for validation, error handling, and submission workflows
-
Accessibility Compliance - WCAG implementation strategies and screen reader optimization
-
Design System Integration - Token usage, theming, and consistent styling across applications
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.