Skip to content

Pending Review

Pending Review from User Experience (UX)

Radio Component

Overview

The PWC Radio component provides single-selection functionality from a group of mutually exclusive options with flexible layout orientation and integrated form validation. Built on the InputBase foundation, it offers horizontal and vertical layouts, individual option disabling, and seamless integration with the PWC form system for comprehensive data collection workflows.

Core Capabilities

  • Single Selection Logic - Mutually exclusive option selection with automatic deselection of other choices within the same group
  • Flexible Layout Orientation - Horizontal and vertical arrangement options for optimal space utilization and user experience
  • Individual Option Control - Granular disabled state management for specific options while maintaining group functionality
  • Form Integration - Seamless connection with PWC forms, validation contexts, and data management systems
  • Loading State Support - Skeleton rendering during form loading with consistent visual feedback for all radio options
  • Accessibility Compliance - Full keyboard navigation, screen reader support, and semantic HTML structure for inclusive design

When to use Radio:

  • Single-choice selection from 2-7 predefined options where users must choose exactly one value
  • Settings and preferences interfaces requiring mutually exclusive configuration options with clear visual hierarchy
  • Survey and form questions needing single-answer responses with logical option grouping and validation
  • Filter interfaces where only one filter value can be active at a time for search or data display

When not to use Radio:

  • Multiple selection scenarios where users need to choose several options simultaneously
  • Single boolean choices where checkbox components provide more appropriate yes/no interaction patterns
  • Large option sets (8+ choices) where select dropdowns offer better space efficiency and user experience

Basic Implementation

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

function PreferencesForm() {
  const [preferences, setPreferences] = useState({
    theme: 'light'
  });

  const themeOptions = [
    { label: 'Light theme', value: 'light' },
    { label: 'Dark theme', value: 'dark' }
  ];

  const handlePreferenceChange = (field: string, value: string) => {
    setPreferences(prev => ({ ...prev, [field]: value }));
    console.log(`${field} changed to:`, value);
  };

  return (
    <PwcRadio
      name="theme"
      label="Display Theme"
      hint="Choose your preferred interface theme"
      options={themeOptions}
      orientation="horizontal"
      value={preferences.theme}
      required
      onChange={(e) => handlePreferenceChange('theme', e.detail)}
    />
  );
}
import { useEffect, useMemo, useRef, useState } from 'react';
import '@progress-i360/progress-web-components/button';
import '@progress-i360/progress-web-components/radio';

type RadioElement = HTMLElement & {
  options?: Array<{ label: string; value: string; disabled?: boolean }>;
  value?: string;
  disabled?: boolean;
};

function SystemConfigurationForm() {
  const deploymentRef = useRef<RadioElement | null>(null);
  const submitButtonRef = useRef<HTMLElement | null>(null);

  const options = useMemo(
    () => [
      { label: 'Development', value: 'development' },
      { label: 'Staging', value: 'staging' }
    ],
    []
  );

  const [settings, setSettings] = useState({ deployment: 'staging', isSaving: false });

  useEffect(() => {
    const radioElement = deploymentRef.current;
    if (!radioElement) {
      return;
    }

    radioElement.options = options;
    radioElement.value = settings.deployment;
    radioElement.disabled = settings.isSaving;

    const handleChange = (event: Event) => {
      const detail = (event as CustomEvent<string>).detail;
      setSettings((prev) => ({ ...prev, deployment: detail }));
    };

    radioElement.addEventListener('pwc-change', handleChange);
    return () => {
      radioElement.removeEventListener('pwc-change', handleChange);
    };
  }, [options, settings.deployment, settings.isSaving]);

  useEffect(() => {
    const button = submitButtonRef.current;
    if (!button) {
      return;
    }

    const handleSubmit = () => {
      if (settings.isSaving) {
        return;
      }

      setSettings((prev) => ({ ...prev, isSaving: true }));
      setTimeout(() => {
        setSettings((prev) => ({ ...prev, isSaving: false }));
      }, 1500);
    };

    button.addEventListener('pwc-click', handleSubmit);
    return () => button.removeEventListener('pwc-click', handleSubmit);
  }, [settings.isSaving]);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
      <pwc-radio
        ref={deploymentRef}
        name="deployment"
        label="Deployment Environment"
        hint="Select the target environment"
        orientation="horizontal"
        required
      ></pwc-radio>

      <pwc-button
        ref={submitButtonRef}
        label={settings.isSaving ? 'Saving...' : 'Save Configuration'}
        variant="primary"
        disabled={settings.isSaving}
      ></pwc-button>
    </div>
  );
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/radio";

@Component({
  selector: 'radio-demo',
  template: `
    <pwc-radio 
      label="Theme Preference" 
      name="theme"
      [options]="themeOptions"
      [value]="selectedTheme"
      orientation="horizontal"
      hint="Choose your preferred interface theme"
      (pwc-change)="selectTheme($event)">
    </pwc-radio>

    <pwc-radio 
      label="Notification Frequency" 
      name="notifications"
      [options]="notificationOptions"
      [value]="selectedFrequency"
      orientation="vertical"
      required
      hint="How often would you like to receive updates?"
      (pwc-change)="updateFrequency($event)">
    </pwc-radio>

    <pwc-radio 
      label="Data Export Format" 
      name="format"
      [options]="formatOptions"
      [value]="selectedFormat"
      orientation="horizontal"
      [disabled]="!canExport"
      (pwc-change)="selectFormat($event)">
    </pwc-radio>

    <div class="preferences-summary" *ngIf="hasSelections">
      <p>Selected: {{ selectedTheme }} theme, {{ selectedFrequency }} notifications, {{ selectedFormat }} format</p>
    </div>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class RadioDemo {
  selectedTheme = 'light';
  selectedFrequency = 'weekly';
  selectedFormat = 'json';
  canExport = true;

  themeOptions = [
    { label: 'Light', value: 'light' },
    { label: 'Dark', value: 'dark' },
    { label: 'Auto', value: 'auto' }
  ];

  notificationOptions = [
    { label: 'Daily', value: 'daily' },
    { label: 'Weekly', value: 'weekly' },
    { label: 'Monthly', value: 'monthly' },
    { label: 'Never', value: 'never' }
  ];

  formatOptions = [
    { label: 'JSON', value: 'json' },
    { label: 'CSV', value: 'csv' },
    { label: 'XML', value: 'xml', disabled: true }
  ];

  get hasSelections() {
    return this.selectedTheme || this.selectedFrequency || this.selectedFormat;
  }

  selectTheme(event: any) {
    this.selectedTheme = event.detail;
    this.canExport = this.selectedTheme !== 'auto';
  }

  updateFrequency(event: any) {
    this.selectedFrequency = event.detail;
  }

  selectFormat(event: any) {
    this.selectedFormat = event.detail;
  }
}
import '@progress-i360/progress-web-components/radio';

const radio = document.createElement('pwc-radio');
radio.setAttribute('label', 'Theme Selection');
radio.setAttribute('name', 'theme');
radio.setAttribute('orientation', 'vertical');

radio.options = [
  { label: 'Light Theme', value: 'light' },
  { label: 'Dark Theme', value: 'dark' },
  { label: 'Auto Theme', value: 'auto' }
];

radio.addEventListener('pwc-change', (event) => {
  console.log('Selected theme:', event.detail);
});

document.body.appendChild(radio);

Usage Patterns

  • Settings and Preferences - User configuration interfaces with mutually exclusive options for themes, layouts, and system behavior
  • Survey and Forms - Single-answer questions requiring one choice from predefined options with clear validation requirements
  • Filter Controls - Search and data filtering interfaces where only one filter value can be active at a time
  • Configuration Wizards - Step-by-step setup processes requiring single selections for system parameters and user preferences

Best Practices

Content Strategy Guidelines

  • Clear Option Labels - Use descriptive, concise labels that clearly differentiate between choices and avoid ambiguous terminology
  • Logical Option Ordering - Arrange options in a logical sequence such as alphabetical, numerical, or by frequency of use
  • Helpful Context Hints - Provide guidance about the impact and implications of different choices for informed decision-making
  • Appropriate Option Count - Limit radio groups to 2-7 options for optimal usability and cognitive load management

Performance Optimization

  • Efficient Option Rendering - Use lightweight option structures and avoid complex nested components within radio options
  • Skeleton Loading Integration - Properly handle loading states during form initialization and data fetching operations
  • Event Handling Optimization - Use single change handlers rather than multiple event listeners for better performance
  • Conditional Disabled States - Implement dynamic option disabling efficiently without unnecessary re-renders

Integration Architecture

  • Form Context Coordination - Integrate seamlessly with PWC form systems for validation, submission, and error handling workflows
  • Orientation Flexibility - Choose horizontal layout for 2-4 short options and vertical layout for longer labels or more options
  • Accessibility Standards - Ensure proper ARIA attributes, keyboard navigation, and screen reader compatibility for inclusive design
  • Design Token Usage - Leverage PWC design tokens for consistent styling, spacing, and color usage across radio components

Common Use Cases

Data Table Headers

  • Column sorting options with single-direction selection (ascending, descending, or default) for data organization
  • View mode selection with mutually exclusive display options (table, grid, or list views) for data presentation
  • Filter categories with single-choice filtering for focused data analysis and user experience optimization

Search Result Sections

  • Sort criteria selection with single sorting method (relevance, date, popularity) for result organization and user control
  • Time range filters with exclusive period selection (today, week, month, year) for temporal data filtering
  • Content type filters with single category selection (documents, images, videos) for focused search results

Dashboard Widget Headers

  • Data aggregation options with single calculation method (sum, average, count) for metric display and analysis
  • Time period selection with exclusive date range options (daily, weekly, monthly) for trend visualization
  • Chart type selection with single visualization method (line, bar, pie) for data presentation flexibility

Troubleshooting

Common Issues

Actions Not Triggering

Symptoms: Radio button selection doesn't update values or change events don't fire properly

Solutions:

  • Verify that radio buttons share the same name attribute for proper group behavior and mutual exclusion

  • Check that onChange handlers are properly bound and contain valid function references for event processing

  • Ensure disabled states don't prevent legitimate user interactions or interfere with selection logic

Actions Not Visible

Symptoms: Radio buttons don't appear or render with missing visual indicators and styling

Solutions:

  • Confirm that radio button styling appears correctly with proper circular indicators and selection states

  • Check that options array contains valid label and value pairs with appropriate data structure

  • Verify CSS styling doesn't hide radio buttons or interfere with component layout and visual hierarchy

Layout Issues

Symptoms: Radio groups appear with incorrect spacing, alignment, or orientation in form layouts

Solutions:

  • Use appropriate orientation (horizontal for short options, vertical for longer labels) based on content and space

  • Check that container styling accommodates chosen orientation and provides adequate spacing between options

  • Ensure gap and padding values from design system tokens provide consistent spacing and visual hierarchy

Icon Problems

Symptoms: Radio button indicators don't display correctly or selection states don't appear visually

Solutions:

  • Verify that radio button circular indicators render with proper border styles and checked state appearance

  • Check that focus indicators and selection states work correctly with keyboard navigation and mouse interaction

  • Ensure color contrast meets accessibility standards for both checked and unchecked radio button states

Implementation Support

  • Form Integration Guidance - Best practices for connecting radio groups with form validation, submission, and error handling systems
  • Accessibility Compliance - WCAG guidelines implementation, keyboard navigation patterns, and screen reader optimization for radio groups
  • Layout Optimization - Orientation selection strategies, spacing considerations, and responsive design patterns for different screen sizes

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.