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.