Select
Accessible dropdown component supporting single and multiple selection with keyboard navigation and validation
Installation
npm install --save @godaddy/antaresProps
label?string | undefined—Visible label above the trigger Required if aria-label is not provided
autoFocus?boolean | undefined—Focus on mount
childrenReactNode | ((item: T) => ReactNode)—SelectItem elements or render function
className?string | undefined—Component CSS class
defaultOpen?boolean | undefined—Default open state (uncontrolled)
defaultSelectedKey?RACKey | undefined—Initial selected key (uncontrolled)
description?string | undefined—Help text below the trigger
errorMessage?string | undefined—Error text shown when invalid
isDisabled?boolean | undefined—Disables interaction
isInvalid?boolean | undefined—Shows error styling and errorMessage
isOpen?boolean | undefined—Open state (controlled)
isRequired?boolean | undefined—Shows red asterisk, requires value for submission
items?Iterable<T> | undefined—Items for dynamic rendering (children must be render function)
labelStyle?"default" | "float" | undefined'default'Label positioning style
name?string | undefined—Form submission name
onOpenChange?((isOpen: boolean) => void) | undefined—Called when open state changes
onSelectionChange?((key: RACKey | null) => void) | undefined—Called when selection changes
placeholder?string | undefined—Placeholder text when empty
selectedKey?RACKey | null | undefined—Selected key (controlled)
selectionMode?"single" | "multiple" | undefined'single'Whether single or multiple selection is enabled
size?"sm" | "md" | undefined'md'Visual size variant
Examples
Static
import { Select, SelectItem } from '@godaddy/antares';export function SelectStaticExample() { return ( <Select aria-label="Coffee drinks"> <SelectItem id="espresso">Espresso</SelectItem> <SelectItem id="latte">Latte</SelectItem> <SelectItem id="cappuccino">Cappuccino</SelectItem> <SelectItem id="americano">Americano</SelectItem> <SelectItem id="mocha">Mocha</SelectItem> </Select> );}Controlled
import { useState } from 'react';import { Box, Flex, Select, SelectItem } from '@godaddy/antares';export function SelectControlledExample() { const [selectedKey, setSelectedKey] = useState<string>('latte'); return ( <Flex direction="column" gap="md"> <Select aria-label="Coffee drinks" selectedKey={selectedKey} onSelectionChange={(key) => setSelectedKey(key as string)} > <SelectItem id="espresso">Espresso</SelectItem> <SelectItem id="latte">Latte</SelectItem> <SelectItem id="cappuccino">Cappuccino</SelectItem> <SelectItem id="americano">Americano</SelectItem> <SelectItem id="mocha">Mocha</SelectItem> </Select> <Box padding="md" elevation="card" rounding="lg"> <strong>Selected:</strong> {selectedKey} </Box> </Flex> );}Dynamic Items
import { Select, SelectItem } from '@godaddy/antares';const items = [ { id: '1', name: 'Espresso', category: 'Classic' }, { id: '2', name: 'Latte', category: 'Classic' }, { id: '3', name: 'Cappuccino', category: 'Classic' }, { id: '4', name: 'Americano', category: 'Classic' }, { id: '5', name: 'Mocha', category: 'Specialty' }, { id: '6', name: 'Macchiato', category: 'Specialty' }, { id: '7', name: 'Cold Brew', category: 'Cold' }];export function SelectDynamicExample() { return ( <Select aria-label="Coffee drinks" items={items}> {function renderItem(item) { return ( <SelectItem id={item.id} textValue={item.name}> {item.name} ({item.category}) </SelectItem> ); }} </Select> );}Multiple Selection
import { Select, SelectItem } from '@godaddy/antares';export function SelectMultipleExample() { return ( <Select aria-label="Coffee drinks" selectionMode="multiple"> <SelectItem id="espresso">Espresso</SelectItem> <SelectItem id="latte">Latte</SelectItem> <SelectItem id="cappuccino">Cappuccino</SelectItem> <SelectItem id="americano">Americano</SelectItem> <SelectItem id="mocha">Mocha</SelectItem> </Select> );}Customization
Data Attributes
React Aria Components automatically adds data attributes for styling different states:
Select Container: data-invalid, data-disabled, data-required, data-focused
Trigger Button: data-pressed, data-disabled, data-focused, aria-expanded
Select Value: data-placeholder
Popover: data-entering, data-exiting
List Items: data-hovered, data-focused, data-pressed, data-selected, data-disabled, data-selection-mode
[data-selected] {
background-color: #eff6ff;
font-weight: 600;
}
[data-invalid] .button {
border-color: #dc2626;
}
[aria-expanded="true"] {
border-color: #3b82f6;
}Component Customization
Individual child components can be styled by passing className props:
<Select label="Coffee">
<SelectItem id="espresso" className="premium-option">
Espresso
</SelectItem>
<SelectSection className="featured-section">
<SelectHeader>Featured</SelectHeader>
<SelectItem id="special">Special Blend</SelectItem>
</SelectSection>
</Select>Accessibility
Keyboard Navigation
- Space/Enter: Opens the popover and focuses the selected item
- Arrow Down/Up: Navigate through options
- Home/End: Jump to first/last option
- Escape: Closes the popover
- Tab: Moves focus to the next focusable element
- Type to select: Type characters to jump to matching options
- Space (in multi-select): Toggle selection of focused item
Troubleshooting
Selection Not Updating
// ❌ Wrong: Using both value and defaultValue
<Select value={value} defaultValue="espresso">
<SelectItem id="espresso">Espresso</SelectItem>
</Select>
// ✅ Controlled mode
<Select value={value} onChange={setValue}>
<SelectItem id="espresso">Espresso</SelectItem>
</Select>
// ✅ Uncontrolled mode
<Select defaultValue="espresso">
<SelectItem id="espresso">Espresso</SelectItem>
</Select>Styling Overrides Not Applying
/* ❌ May not have enough specificity */
.item {
background-color: red;
}
/* ✅ Use data attributes for higher specificity */
.my-select [data-selected] {
background-color: red;
}Keyboard Navigation Not Working
/* ❌ Don't remove focus outlines without replacement */
.button:focus {
outline: none;
}
/* ✅ Provide visible focus indicator */
.button:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}