Skip to content

Pending Review

Pending Review from User Experience (UX)

Select Component

Overview

The PWC Select component provides a dropdown selection interface with floating menu positioning, keyboard navigation, and comprehensive form integration. Built on the InputBase foundation with Floating UI positioning system, it offers single-option selection from predefined lists with validation support, loading states, and seamless PWC form system integration for complex data collection workflows.

Core Capabilities

  • Floating Menu Positioning - Advanced dropdown positioning with automatic flip and shift behavior for optimal viewport placement
  • Single Option Selection - Streamlined selection from predefined option lists with clear visual feedback and state management
  • Keyboard Navigation Support - Full keyboard accessibility with arrow keys, Enter, and Escape key handling for inclusive user experience
  • Form Integration - Seamless connection with PWC forms, validation contexts, and data management systems with real-time validation
  • Loading State Support - Skeleton rendering during form loading with consistent visual feedback and progressive enhancement
  • Size Variants - Standard and long width options to accommodate different layout requirements and content lengths

When to use Select:

  • Single-choice selection from 3+ predefined options where dropdown menus provide better space efficiency than radio buttons
  • Form fields requiring selection from large option sets (10+ choices) where visual scanning is more efficient than radio layouts
  • Data entry interfaces needing validated single selections with clear option labels and structured value management
  • Settings and configuration panels where dropdown selections provide clean, compact interface organization

When not to use Select:

  • Binary or very few options (2-3 choices) where radio buttons provide better immediate visibility and decision clarity
  • Multiple selection scenarios where checkbox groups or multi-select components offer appropriate interaction patterns
  • Search-driven selection where autocomplete or search input components provide better user experience for large datasets

Basic Implementation

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

function UserPreferencesForm() {
  const [preferences, setPreferences] = useState({
    country: '',
    language: ''
  });

  const countryOptions = useMemo(
    () => [
      { label: 'United States', value: 'us' },
      { label: 'Canada', value: 'ca' }
    ],
    []
  );

  const languageOptions = useMemo(
    () => [
      { label: 'English', value: 'en' },
      { label: 'Spanish', value: 'es' }
    ],
    []
  );

  const handlePreferenceChange = (field: string, value: string) => {
    setPreferences((previous) => ({ ...previous, [field]: value }));
  };

  return (
    <>
      <PwcSelect
        name="country"
        label="Country"
        hint="Select your country of residence"
        options={countryOptions}
        placeholder="Choose a country"
        value={preferences.country}
        required
        autoFocus
        onChange={(event) => handlePreferenceChange('country', event.detail)}
      />

      <PwcSelect
        name="language"
        label="Language"
        hint="Select interface language"
        options={languageOptions}
        placeholder="Choose language"
        value={preferences.language}
        onChange={(event) => handlePreferenceChange('language', event.detail)}
      />
    </>
  );
}
import { useEffect, useMemo, useRef, useState } from 'react';
import '@progress-i360/progress-web-components/button';
import '@progress-i360/progress-web-components/form';
import '@progress-i360/progress-web-components/select';

type SelectOption = { label: string; value: string };

type SelectElement = HTMLElement & {
  options?: SelectOption[];
  value?: string;
  placeholder?: string;
  disabled?: boolean;
  required?: boolean;
};

type ButtonElement = HTMLElement & {
  label?: string;
  disabled?: boolean;
  variant?: string;
};

type PwcSubmitDetail = {
  payload: Record<string, unknown>;
  success: () => void;
};

function SystemConfigurationForm() {
  const formRef = useRef<HTMLElement | null>(null);
  const environmentSelectRef = useRef<SelectElement | null>(null);
  const databaseSelectRef = useRef<SelectElement | null>(null);
  const submitButtonRef = useRef<ButtonElement | null>(null);

  const environmentOptions = useMemo<SelectOption[]>(
    () => [
      { label: 'Development', value: 'development' },
      { label: 'Production', value: 'production' }
    ],
    []
  );

  const databaseOptions = useMemo<SelectOption[]>(
    () => [
      { label: 'PostgreSQL', value: 'postgresql' },
      { label: 'MySQL', value: 'mysql' }
    ],
    []
  );

  const [config, setConfig] = useState({
    environment: 'development',
    database: 'postgresql'
  });

  const [isSubmitting, setIsSubmitting] = useState(false);

  useEffect(() => {
    const environmentSelect = environmentSelectRef.current;
    if (!environmentSelect) {
      return;
    }

    environmentSelect.options = environmentOptions;
    environmentSelect.value = config.environment;
    environmentSelect.placeholder = 'Choose environment';
    environmentSelect.disabled = isSubmitting;
    environmentSelect.required = true;

    const handleEnvironmentChange = (event: Event) => {
      const detail = (event as CustomEvent<string>).detail;
      setConfig(previous => ({ ...previous, environment: detail }));
    };

    environmentSelect.addEventListener('pwc-change', handleEnvironmentChange);
    return () => {
      environmentSelect.removeEventListener('pwc-change', handleEnvironmentChange);
    };
  }, [config.environment, environmentOptions, isSubmitting]);

  useEffect(() => {
    const databaseSelect = databaseSelectRef.current;
    if (!databaseSelect) {
      return;
    }

    databaseSelect.options = databaseOptions;
    databaseSelect.value = config.database;
    databaseSelect.placeholder = 'Select database';
    databaseSelect.disabled = isSubmitting;
    databaseSelect.required = true;

    const handleDatabaseChange = (event: Event) => {
      const detail = (event as CustomEvent<string>).detail;
      setConfig(previous => ({ ...previous, database: detail }));
    };

    databaseSelect.addEventListener('pwc-change', handleDatabaseChange);
    return () => {
      databaseSelect.removeEventListener('pwc-change', handleDatabaseChange);
    };
  }, [config.database, databaseOptions, isSubmitting]);

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

    button.label = isSubmitting ? 'Configuring...' : 'Deploy Configuration';
    button.disabled = isSubmitting;
    button.variant = 'primary';
  }, [isSubmitting]);

  useEffect(() => {
    const formElement = formRef.current;
    if (!formElement) {
      return;
    }

    const handleSubmit = (event: Event) => {
      const submitDetail = (event as CustomEvent<PwcSubmitDetail>).detail;
      if (!submitDetail || isSubmitting) {
        return;
      }

      setIsSubmitting(true);
      setTimeout(() => {
        submitDetail.success();
        setIsSubmitting(false);
      }, 2000);
    };

    formElement.addEventListener('pwc-submit', handleSubmit as EventListener);
    return () => {
      formElement.removeEventListener('pwc-submit', handleSubmit as EventListener);
    };
  }, [isSubmitting]);

  return (
    <pwc-form ref={formRef}>
      <pwc-select
        ref={environmentSelectRef}
        name="environment"
        label="Deployment Environment"
        hint="Select target environment"
      ></pwc-select>

      <pwc-select
        ref={databaseSelectRef}
        name="database"
        label="Database System"
        hint="Choose primary database technology"
      ></pwc-select>

      <pwc-button
        ref={submitButtonRef}
        type="submit"
        style={{ marginTop: '16px' }}
      ></pwc-button>
    </pwc-form>
  );
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/select";

@Component({
  selector: 'select-demo',
  template: `
    <pwc-select 
      label="Country" 
      placeholder="Select your country"
      [options]="countryOptions"
      [value]="selectedCountry"
      required
      hint="This affects shipping and tax calculations"
      (pwc-change)="updateCountry($event)">
    </pwc-select>

    <pwc-select 
      label="State/Province" 
      placeholder="Select state or province"
      [options]="stateOptions"
      [value]="selectedState"
      [disabled]="!selectedCountry"
      [long]="true"
      (pwc-change)="updateState($event)">
    </pwc-select>

    <pwc-select 
      label="Language" 
      placeholder="Choose interface language"
      [options]="languageOptions"
      [value]="selectedLanguage"
      hint="Interface will update immediately"
      (pwc-change)="updateLanguage($event)">
    </pwc-select>

    <pwc-select 
      label="Time Zone" 
      placeholder="Select your time zone"
      [options]="timezoneOptions"
      [value]="selectedTimezone"
      [disabled]="isLoading"
      (pwc-change)="updateTimezone($event)">
    </pwc-select>

    <div class="selection-summary" *ngIf="hasSelections">
      <p>Location: {{ getLocationString() }}</p>
      <p>Interface: {{ selectedLanguage }} language, {{ selectedTimezone }} timezone</p>
    </div>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class SelectDemo {
  selectedCountry = '';
  selectedState = '';
  selectedLanguage = 'en';
  selectedTimezone = '';
  isLoading = false;

  countryOptions = [
    { label: 'United States', value: 'us' },
    { label: 'Canada', value: 'ca' },
    { label: 'United Kingdom', value: 'uk' },
    { label: 'Germany', value: 'de' },
    { label: 'France', value: 'fr' }
  ];

  languageOptions = [
    { label: 'English', value: 'en' },
    { label: 'Spanish', value: 'es' },
    { label: 'French', value: 'fr' },
    { label: 'German', value: 'de' },
    { label: 'Italian', value: 'it' }
  ];

  timezoneOptions = [
    { label: 'Eastern Time (ET)', value: 'et' },
    { label: 'Central Time (CT)', value: 'ct' },
    { label: 'Mountain Time (MT)', value: 'mt' },
    { label: 'Pacific Time (PT)', value: 'pt' },
    { label: 'Coordinated Universal Time (UTC)', value: 'utc' }
  ];

  get stateOptions() {
    const stateMap: { [key: string]: any[] } = {
      'us': [
        { label: 'California', value: 'ca' },
        { label: 'New York', value: 'ny' },
        { label: 'Texas', value: 'tx' },
        { label: 'Florida', value: 'fl' }
      ],
      'ca': [
        { label: 'Ontario', value: 'on' },
        { label: 'Quebec', value: 'qc' },
        { label: 'British Columbia', value: 'bc' },
        { label: 'Alberta', value: 'ab' }
      ]
    };
    return stateMap[this.selectedCountry] || [];
  }

  get hasSelections() {
    return this.selectedCountry || this.selectedLanguage;
  }

  updateCountry(event: CustomEvent<string>) {
    this.selectedCountry = event.detail;
    this.selectedState = ''; // Reset state when country changes
  }

  updateState(event: CustomEvent<string>) {
    this.selectedState = event.detail;
  }

  updateLanguage(event: CustomEvent<string>) {
    this.selectedLanguage = event.detail;
    this.simulateLanguageChange();
  }

  updateTimezone(event: CustomEvent<string>) {
    this.selectedTimezone = event.detail;
  }

  getLocationString(): string {
    const country = this.countryOptions.find(c => c.value === this.selectedCountry)?.label || '';
    const state = this.stateOptions.find(s => s.value === this.selectedState)?.label || '';
    return state ? `${state}, ${country}` : country;
  }

  private simulateLanguageChange() {
    this.isLoading = true;
    setTimeout(() => {
      this.isLoading = false;
    }, 1000);
  }
}
import '@progress-i360/progress-web-components/select';

const selectDropdown = document.createElement('pwc-select');
selectDropdown.label = 'Choose Country';
selectDropdown.placeholder = 'Select a country...';
selectDropdown.name = 'country';

selectDropdown.options = [
  { label: 'United States', value: 'us' },
  { label: 'Canada', value: 'ca' },
  { label: 'United Kingdom', value: 'uk' }
];

selectDropdown.addEventListener('pwc-change', event => {
  console.log('Country selected:', event.detail);
});

document.body.appendChild(selectDropdown);

Usage Patterns

  • Form Data Entry - User registration, profile setup, and data collection forms requiring single selections from predefined options
  • Configuration Interfaces - System settings, user preferences, and application configuration with organized dropdown selections
  • Filter and Sort Controls - Data table filtering, search result sorting, and content organization with clear selection criteria
  • Dependent Selection Chains - Cascading dropdowns where selections trigger updates to related option lists and form fields

Best Practices

Content Strategy Guidelines

  • Clear Option Labels - Use descriptive, scannable labels that clearly differentiate between choices and avoid ambiguous terminology
  • Logical Option Ordering - Arrange options in intuitive sequences such as alphabetical, frequency of use, or logical progression
  • Appropriate Placeholder Text - Provide helpful placeholder guidance that indicates the type of selection expected without being redundant
  • Strategic Option Disabling - Use disabled options judiciously to indicate temporarily unavailable choices while maintaining context

Performance Optimization

  • Efficient Option Rendering - Use lightweight option structures and avoid complex nested components within dropdown menu items
  • Menu Positioning Optimization - Leverage Floating UI positioning system efficiently to prevent layout shifts and viewport overflow
  • Debounced Interaction Handling - Implement appropriate debouncing for blur events and menu state changes to optimize performance
  • Loading State Integration - Properly handle skeleton rendering during form initialization and option loading operations

Integration Architecture

  • Form Context Coordination - Integrate seamlessly with PWC form systems for validation, submission, and error handling workflows
  • Size Variant Selection - Choose standard width variants for most use cases and long variants for options with extended label text
  • Accessibility Standards - Ensure proper ARIA attributes, keyboard navigation, and screen reader compatibility for dropdown interactions
  • Design Token Usage - Leverage PWC design tokens for consistent styling, spacing, and color usage across select components

Common Use Cases

Data Table Headers

  • Column sorting options with dropdown selections for sort criteria and direction preferences
  • Filter presets with predefined filter combinations for common data analysis scenarios
  • View configuration dropdowns for table density, column visibility, and display preferences

Search Result Sections

  • Sort criteria selection with options for relevance, date, popularity, and custom sorting parameters
  • Results per page configuration with standard pagination options and user preference storage
  • Content type filtering with dropdown selections for documents, images, videos, and other media types

Dashboard Widget Headers

  • Data source selection with dropdown options for different data feeds and integration endpoints
  • Time range configuration with preset options for daily, weekly, monthly, and custom date ranges
  • Chart type selection with visualization options for different data presentation methods and formats

Troubleshooting

Common Issues

Actions Not Triggering

Symptoms: Dropdown doesn't open, selections don't register, or change events don't fire properly

Solutions:

  • Verify that button element is not disabled and click handlers are properly bound to functional event listeners

  • Check that option data structure contains valid label and value pairs with appropriate data types and formatting

  • Ensure dropdown menu positioning doesn't interfere with click detection or event propagation mechanisms

Actions Not Visible

Symptoms: Dropdown menu doesn't appear, options don't render, or menu appears in wrong location

Solutions:

  • Confirm that Floating UI positioning system is properly initialized and configured for your layout context

  • Check that menu styling and z-index values allow proper visibility above other page content and interface elements

  • Verify that option arrays contain valid data and render correctly within the dropdown menu structure

Layout Issues

Symptoms: Select component appears with incorrect width, alignment, or spacing in form layouts

Solutions:

  • Use appropriate size variants (standard vs long) based on option label lengths and available layout space

  • Check that container styling accommodates select component requirements and provides adequate spacing for dropdown expansion

  • Ensure responsive design patterns work correctly across different screen sizes and device orientations

Icon Problems

Symptoms: Chevron icons don't display correctly or don't rotate properly when dropdown opens/closes

Solutions:

  • Verify that chevron-up and chevron-down icons are available in your icon system and configured correctly

  • Check that icon color theming works properly for normal and disabled states with appropriate contrast ratios

  • Ensure icon animations and state transitions function smoothly during dropdown open/close interactions

Implementation Support

  • Option Management Strategies - Best practices for organizing large option sets, implementing search functionality, and managing dynamic option updates
  • Accessibility Compliance - WCAG guidelines implementation, keyboard navigation patterns, and screen reader optimization for dropdown selections
  • Form Integration Patterns - Strategies for connecting select components with validation systems, dependent field updates, and form submission workflows

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.