# SelectAlpha A flexible select component for both single and multi-selection, built for web applications with comprehensive accessibility support. ## Import ```tsx import { Select } from '@coinbase/cds-web/alpha/select' ``` ## Examples :::note Duplicate Values Avoid using options with duplicate values. Each option's `value` should be unique within the options array to ensure proper selection behavior. ::: ### Single Select Basic single selection with predefined options. ```jsx live function SingleSelectExample() { const [value, setValue] = useState('1'); const options = [ { value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }, { value: '3', label: 'Option 3' }, { value: '4', label: 'Option 4' }, ]; return ( ); } ``` ### Single Select with Groups Organize options into logical groups for better organization. ```jsx live function SingleSelectWithGroupsExample() { const [value, setValue] = useState(null); const groupedOptions = [ { label: 'Group A', options: [ { value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }, { value: '3', label: 'Option 3' }, ], }, { label: 'Group B', options: [ { value: '4', label: 'Option 4' }, { value: '5', label: 'Option 5' }, ], }, { label: 'Group C', options: [{ value: '6', label: 'Option 6' }], }, ]; return ( ); } ``` ### Accessibility Props The Select component supports comprehensive accessibility features including custom labels and roles. ```jsx live function AccessibilityExample() { const [value, setValue] = useState('2'); const options = [ { value: '1', label: 'High Priority' }, { value: '2', label: 'Medium Priority' }, { value: '3', label: 'Low Priority' }, ]; return ( ); } ``` ### Compact Mode The Select component can be rendered in a compact size for denser UIs. ```jsx live function CompactExample() { const [value, setValue] = useState('1'); const options = [ { value: '1', label: 'Small Option 1' }, { value: '2', label: 'Small Option 2' }, { value: '3', label: 'Small Option 3' }, ]; return ( ); } ``` ### Disabled States Components can be disabled entirely or have individual options disabled. ```jsx live function DisabledExample() { const [value1, setValue1] = useState('2'); const [value2, setValue2] = useState('2'); const optionsWithDisabled = [ { value: '1', label: 'Option 1', disabled: true }, { value: '2', label: 'Option 2' }, { value: '3', label: 'Option 3' }, { value: '4', label: 'Option 4', disabled: true }, ]; return ( ); } ``` ### Options with Descriptions Options can include descriptions for additional context. ```jsx live function DescriptionExample() { const [value, setValue] = useState('1'); const optionsWithDescriptions = [ { value: '1', label: 'Bitcoin', description: 'The first cryptocurrency' }, { value: '2', label: 'Ethereum', description: 'Smart contract platform' }, { value: '3', label: 'USDC', description: 'USD-backed stablecoin' }, { value: '4', label: 'Solana', description: 'High-performance blockchain' }, ]; return ( } placeholder="Search for options" /> ); } ``` ### End Node Add an icon or element at the end of the select control. ```jsx live function EndNodeExample() { const [value, setValue] = useState('1'); const options = [ { value: '1', label: 'Search Result 1' }, { value: '2', label: 'Search Result 2' }, { value: '3', label: 'Search Result 3' }, ]; return ( ); } ``` ### Empty State Handle empty option lists with custom messages or components. ```jsx live function EmptyStateExample() { const [searchTerm, setSearchTerm] = useState(''); const [value, setValue] = useState(null); const allOptions = []; const filteredOptions = searchTerm ? allOptions.filter((opt) => opt.label.toLowerCase().includes(searchTerm.toLowerCase())) : allOptions; return ( ); } ``` ### Multi-Select with Max Display Limit the number of selected items shown when using multi-select. ```jsx live function MaxDisplayExample() { const { value, onChange } = useMultiSelect({ initialValue: ['1', '2', '3', '4', '5'], }); const options = Array.from({ length: 20 }, (_, i) => ({ value: (i + 1).toString(), label: `Option ${i + 1}`, })); return ( ); } ``` ### Label Variants Different label positioning options for the Select component. ```jsx live function LabelVariantExample() { const [value1, setValue1] = useState(''); const [value2, setValue2] = useState(''); const options = [ { value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }, { value: '3', label: 'Option 3' }, ]; return ( ); } ``` ### Very Long Labels Handle extremely long option labels that may need special treatment. ```jsx live function VeryLongLabelsExample() { const [value, setValue] = useState('1'); const longOptions = [ { value: '1', label: 'This is an extremely long option label that should test how the component handles very long text content that might overflow or wrap', }, { value: '2', label: 'Another super long option label with even more text to see how it wraps or truncates in the UI when space is limited', }, { value: '3', label: 'Short', }, { value: '4', label: 'A moderately long label that is somewhere between short and extremely long', }, ]; return ( ); } ``` ### Mixed Options Options with and without descriptions in the same select. ```jsx live function MixedOptionsExample() { const [value, setValue] = useState('1'); const mixedOptions = [ { value: '1', label: 'Bitcoin', description: 'The original cryptocurrency' }, { value: '2', label: 'Ethereum' }, { value: '3', label: 'USDC', description: 'USD-backed stablecoin' }, { value: '4', label: 'Solana' }, { value: '5', label: 'Polygon', description: 'Layer 2 scaling solution' }, ]; return ( ); } ``` ### Options with Only Media Add media icons without accessories for visual identification. ```jsx live function OnlyMediaExample() { const [value, setValue] = useState('1'); const optionsWithMedia = [ { value: '1', label: 'Home', media: , }, { value: '2', label: 'Profile', media: , }, { value: '3', label: 'Settings', media: , }, ]; return ( } label="Compact + Positive + Icon" value={value1} onChange={setValue1} options={options} helperText="Multiple props combined" /> ); } ``` ### No Label Select without a visible label (accessibility label still required). ```jsx live function NoLabelExample() { const [value, setValue] = useState('1'); const options = [ { value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }, { value: '3', label: 'Option 3' }, ]; return ( ); } ``` ### Stress Test Many options with various configurations for performance testing. ```jsx live function StressTestExample() { const [value, setValue] = useState('1'); const stressOptions = Array.from({ length: 50 }, (_, i) => ({ value: (i + 1).toString(), label: `Option ${i + 1}`, description: i % 3 === 0 ? `Description for option ${i + 1}` : undefined, disabled: i % 7 === 0, accessory: i % 5 === 0 ? : undefined, media: i % 8 === 0 ? : undefined, })); return ( ); } ``` ### Options with Only Description Options that only have descriptions without labels. ```jsx live function OnlyDescriptionExample() { const [value, setValue] = useState('1'); const descriptionOnlyOptions = [ { value: '1', description: 'First description without a label' }, { value: '2', description: 'Second description only' }, { value: '3', description: 'Third item with just description' }, { value: '4', description: 'Fourth description-only option' }, ]; return ( ); } ``` ### Custom class names You can use custom class names on the various subcomponents in Select. ```jsx function CustomClassNamesExamples() { const exampleOptions = [ { value: null, label: 'Remove selection' }, { value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }, { value: '3', label: 'Option 3' }, { value: '4', label: 'Option 4' }, ]; const [value, setValue] = useState('1'); return ( Custom Label } value={value} onChange={setValue} options={options} placeholder="Select an option" /> ); } ``` ### Borderless You can remove the border from the select control by setting `bordered` to `false`. Now Select will only show a border when focused. ```jsx live function BorderlessExample() { const [singleValue, setSingleValue] = useState('1'); const { value: multiValue, onChange: multiOnChange } = useMultiSelect({ initialValue: ['1', '2'], }); const options = [ { value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }, { value: '3', label: 'Option 3' }, { value: '4', label: 'Option 4' }, ]; return ( ); } ``` ### Custom components Select is highly customizable. Use the _Component_ props to customize the various subcomponents in Select. #### Customizable subcomponents - **SelectControlComponent**: Trigger component used to open and close the Select. - **SelectDropdownComponent**: Component which renders the dropdown menu and SelectOptionComponents. - **SelectOptionComponent**: Component which renders the content of an option in the select. - **SelectAllOptionComponent**: Component which renders the Select All option in a multi-select select menu. - **SelectEmptyDropdownContentsComponent**: Component which renders as the select menu's content when no options are passed in. Below is a diagram to help visualize the Select anatomy. ```text Select β”œβ”€β”€ SelectControlComponent (trigger to open/close) └── SelectDropdownComponent (dropdown menu) β”œβ”€β”€ SelectAllOptionComponent β”œβ”€β”€ SelectOptionComponent (option 1) β”œβ”€β”€ SelectOptionComponent (option 2) β”œβ”€β”€ SelectOptionComponent (option 3) └── SelectOptionComponent (option N...) ``` #### Example ```jsx function CustomComponentExamples() { const exampleOptions = [ { value: null, label: 'Remove selection' }, { value: '1', label: 'Option 1' }, { value: '2', label: 'Option 2' }, { value: '3', label: 'Option 3' }, { value: '4', label: 'Option 4' }, ]; const [value, setValue] = useState('1'); const CustomControlComponent = ({ value, setOpen }) => { return ; }; const CustomOptionComponent = ({ value, onClick }) => { return ( ); }; return (