Dropdown Component
The Dropdown component provides a customizable select menu with support for searching, keyboard navigation, and accessibility features.
Example
<div style="max-width:300px"><div class="skin-form dropdown-wrapper group "><input type="hidden" value=""/><div class="dropdown"><div class="wrapper" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-owns="dropdown-list-:r0R0:" aria-controls="dropdown-list-:r0R0:"><button id="dropdown-trigger-:r0R0:" class="dropdown-summary interactive" role="combobox" aria-haspopup="listbox" aria-expanded="false" aria-controls="dropdown-list-:r0R0:" aria-labelledby="dropdown-label-:r0R0:" aria-autocomplete="none" type="button"><div class="dropdown-summary-content"><svg class="dropdown-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"></path></svg><span id="selected-value-dropdown-trigger-:r0R0:" class="text-body">Select a fruit</span><svg class="dropdown-icon chevron" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></div></button></div><div class="dropdown-content-wrapper"><ul id="dropdown-list-:r0R0:" class="dropdown-list" role="listbox" aria-labelledby="dropdown-label-:r0R0:" tabindex="-1"><li role="option" id="dropdown-list-:r0R0:-option-1" class="text-body interactive " aria-selected="false" tabindex="-1">Apple</li><li role="option" id="dropdown-list-:r0R0:-option-2" class="text-body interactive " aria-selected="false" tabindex="-1">Banana</li><li role="option" id="dropdown-list-:r0R0:-option-3" class="text-body interactive " aria-selected="false" tabindex="-1">Cherry</li><li role="option" id="dropdown-list-:r0R0:-option-4" class="text-body interactive " aria-selected="false" tabindex="-1">Date</li><li role="option" id="dropdown-list-:r0R0:-option-5" class="text-body interactive " aria-selected="false" tabindex="-1">Elderberry</li><li role="option" id="dropdown-list-:r0R0:-option-6" class="text-body interactive " aria-selected="false" tabindex="-1">Fig</li></ul></div></div></div></div>
<div style="max-width:300px"><div class="skin-form dropdown-wrapper group "><input type="hidden" value=""/><div class="dropdown"><div class="wrapper" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-owns="dropdown-list-:r0R0:" aria-controls="dropdown-list-:r0R0:"><button id="dropdown-trigger-:r0R0:" class="dropdown-summary interactive" role="combobox" aria-haspopup="listbox" aria-expanded="false" aria-controls="dropdown-list-:r0R0:" aria-labelledby="dropdown-label-:r0R0:" aria-autocomplete="none" type="button"><div class="dropdown-summary-content"><svg class="dropdown-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"></path></svg><span id="selected-value-dropdown-trigger-:r0R0:" class="text-body">Select a fruit</span><svg class="dropdown-icon chevron" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></div></button></div><div class="dropdown-content-wrapper"><ul id="dropdown-list-:r0R0:" class="dropdown-list" role="listbox" aria-labelledby="dropdown-label-:r0R0:" tabindex="-1"><li role="option" id="dropdown-list-:r0R0:-option-1" class="text-body interactive " aria-selected="false" tabindex="-1">Apple</li><li role="option" id="dropdown-list-:r0R0:-option-2" class="text-body interactive " aria-selected="false" tabindex="-1">Banana</li><li role="option" id="dropdown-list-:r0R0:-option-3" class="text-body interactive " aria-selected="false" tabindex="-1">Cherry</li><li role="option" id="dropdown-list-:r0R0:-option-4" class="text-body interactive " aria-selected="false" tabindex="-1">Date</li><li role="option" id="dropdown-list-:r0R0:-option-5" class="text-body interactive " aria-selected="false" tabindex="-1">Elderberry</li><li role="option" id="dropdown-list-:r0R0:-option-6" class="text-body interactive " aria-selected="false" tabindex="-1">Fig</li></ul></div></div></div></div>
<div style="max-width:300px;margin-top:20px"><div class="skin-form dropdown-wrapper group "><input type="hidden" value=""/><div class="dropdown"><div class="wrapper" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-owns="dropdown-list-:r1R0:" aria-controls="dropdown-list-:r1R0:"><button id="dropdown-trigger-:r1R0:" class="dropdown-summary interactive" aria-haspopup="listbox" aria-expanded="false" aria-controls="dropdown-list-:r1R0:" aria-labelledby="dropdown-label-:r1R0: selected-value-dropdown-trigger-:r1R0:" type="button"><div class="dropdown-summary-content"><svg class="dropdown-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"></path></svg><span id="selected-value-dropdown-trigger-:r1R0:" class="text-body">Select a country</span><svg class="dropdown-icon chevron" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></div></button></div><div class="dropdown-content-wrapper"><div class="dropdown-search-wrapper wrapper"><div class="search-input-wrapper"><svg class="dropdown-search-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"></path></svg><input id="dropdown-search-:r1R0:" class="dropdown-search-input text-body placeholder:soft" placeholder="Search countries..." type="search" autoComplete="off" value=""/></div></div><ul id="dropdown-list-:r1R0:" class="dropdown-list" role="listbox" aria-labelledby="dropdown-label-:r1R0:" tabindex="-1"><li role="option" id="dropdown-list-:r1R0:-option-1" class="text-body interactive " aria-selected="false" tabindex="-1">United States</li><li role="option" id="dropdown-list-:r1R0:-option-2" class="text-body interactive " aria-selected="false" tabindex="-1">United Kingdom</li><li role="option" id="dropdown-list-:r1R0:-option-3" class="text-body interactive " aria-selected="false" tabindex="-1">Canada</li><li role="option" id="dropdown-list-:r1R0:-option-4" class="text-body interactive " aria-selected="false" tabindex="-1">Australia</li><li role="option" id="dropdown-list-:r1R0:-option-5" class="text-body interactive " aria-selected="false" tabindex="-1">Germany</li><li role="option" id="dropdown-list-:r1R0:-option-6" class="text-body interactive " aria-selected="false" tabindex="-1">France</li><li role="option" id="dropdown-list-:r1R0:-option-7" class="text-body interactive " aria-selected="false" tabindex="-1">Japan</li></ul></div></div></div></div>
<div style="max-width:300px;margin-top:20px"><div class="skin-form dropdown-wrapper group "><input type="hidden" value=""/><div class="dropdown"><div class="wrapper" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-owns="dropdown-list-:r1R0:" aria-controls="dropdown-list-:r1R0:"><button id="dropdown-trigger-:r1R0:" class="dropdown-summary interactive" aria-haspopup="listbox" aria-expanded="false" aria-controls="dropdown-list-:r1R0:" aria-labelledby="dropdown-label-:r1R0: selected-value-dropdown-trigger-:r1R0:" type="button"><div class="dropdown-summary-content"><svg class="dropdown-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"></path></svg><span id="selected-value-dropdown-trigger-:r1R0:" class="text-body">Select a country</span><svg class="dropdown-icon chevron" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></div></button></div><div class="dropdown-content-wrapper"><div class="dropdown-search-wrapper wrapper"><div class="search-input-wrapper"><svg class="dropdown-search-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"></path></svg><input id="dropdown-search-:r1R0:" class="dropdown-search-input text-body placeholder:soft" placeholder="Search countries..." type="search" autoComplete="off" value=""/></div></div><ul id="dropdown-list-:r1R0:" class="dropdown-list" role="listbox" aria-labelledby="dropdown-label-:r1R0:" tabindex="-1"><li role="option" id="dropdown-list-:r1R0:-option-1" class="text-body interactive " aria-selected="false" tabindex="-1">United States</li><li role="option" id="dropdown-list-:r1R0:-option-2" class="text-body interactive " aria-selected="false" tabindex="-1">United Kingdom</li><li role="option" id="dropdown-list-:r1R0:-option-3" class="text-body interactive " aria-selected="false" tabindex="-1">Canada</li><li role="option" id="dropdown-list-:r1R0:-option-4" class="text-body interactive " aria-selected="false" tabindex="-1">Australia</li><li role="option" id="dropdown-list-:r1R0:-option-5" class="text-body interactive " aria-selected="false" tabindex="-1">Germany</li><li role="option" id="dropdown-list-:r1R0:-option-6" class="text-body interactive " aria-selected="false" tabindex="-1">France</li><li role="option" id="dropdown-list-:r1R0:-option-7" class="text-body interactive " aria-selected="false" tabindex="-1">Japan</li></ul></div></div></div></div>
<div style="max-width:300px;margin-top:20px"><div class="skin-form dropdown-wrapper group "><input type="hidden" value=""/><div class="dropdown"><div class="wrapper" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-owns="dropdown-list-:r2R0:" aria-controls="dropdown-list-:r2R0:"><button id="dropdown-trigger-:r2R0:" class="dropdown-summary interactive" role="combobox" aria-haspopup="listbox" aria-expanded="false" aria-controls="dropdown-list-:r2R0:" aria-labelledby="dropdown-label-:r2R0:" aria-autocomplete="none" type="button"><div class="dropdown-summary-content"><svg class="dropdown-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"></path></svg><span id="selected-value-dropdown-trigger-:r2R0:" class="text-body">Select a color</span><svg class="dropdown-icon chevron" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></div></button></div><div class="dropdown-content-wrapper"><ul id="dropdown-list-:r2R0:" class="dropdown-list" role="listbox" aria-labelledby="dropdown-label-:r2R0:" tabindex="-1"><li role="option" id="dropdown-list-:r2R0:-option-1" class="text-body interactive " aria-selected="false" tabindex="-1">Red</li><li role="option" id="dropdown-list-:r2R0:-option-2" class="text-body interactive " aria-selected="false" tabindex="-1">Green</li><li role="option" id="dropdown-list-:r2R0:-option-3" class="text-body interactive " aria-selected="false" tabindex="-1">Blue</li><li role="option" id="dropdown-list-:r2R0:-option-4" class="text-body interactive " aria-selected="false" tabindex="-1">Yellow</li></ul></div></div></div></div>
<div style="max-width:300px;margin-top:20px"><div class="skin-form dropdown-wrapper group "><input type="hidden" value=""/><div class="dropdown"><div class="wrapper" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-owns="dropdown-list-:r2R0:" aria-controls="dropdown-list-:r2R0:"><button id="dropdown-trigger-:r2R0:" class="dropdown-summary interactive" role="combobox" aria-haspopup="listbox" aria-expanded="false" aria-controls="dropdown-list-:r2R0:" aria-labelledby="dropdown-label-:r2R0:" aria-autocomplete="none" type="button"><div class="dropdown-summary-content"><svg class="dropdown-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"></path></svg><span id="selected-value-dropdown-trigger-:r2R0:" class="text-body">Select a color</span><svg class="dropdown-icon chevron" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" focusable="false"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg></div></button></div><div class="dropdown-content-wrapper"><ul id="dropdown-list-:r2R0:" class="dropdown-list" role="listbox" aria-labelledby="dropdown-label-:r2R0:" tabindex="-1"><li role="option" id="dropdown-list-:r2R0:-option-1" class="text-body interactive " aria-selected="false" tabindex="-1">Red</li><li role="option" id="dropdown-list-:r2R0:-option-2" class="text-body interactive " aria-selected="false" tabindex="-1">Green</li><li role="option" id="dropdown-list-:r2R0:-option-3" class="text-body interactive " aria-selected="false" tabindex="-1">Blue</li><li role="option" id="dropdown-list-:r2R0:-option-4" class="text-body interactive " aria-selected="false" tabindex="-1">Yellow</li></ul></div></div></div></div>
Usage
import Dropdown from "@altitude/ui/react/ui/dropdown/dropdown";
export default function DropdownExample() {
const [selectedValue, setSelectedValue] = React.useState("");
const handleChange = (e) => {
setSelectedValue(e.target.value);
options={["Option 1", "Option 2", "Option 3"]}
placeholder="Select an option"
{/* Dropdown with search */}
options={["Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig"]}
placeholder="Select a fruit"
searchPlaceholder="Search fruits..."
{/* Controlled dropdown */}
options={["Red", "Green", "Blue", "Yellow"]}
placeholder="Select a color"
Props
| Prop | Type | Required | Description |
|---|
| options | string[] | Yes | Array of options to display in the dropdown |
| placeholder | string | No | Placeholder text when no option is selected |
| disabled | boolean | No | Whether the dropdown is disabled |
| enableSearch | boolean | No | Enable search functionality (default: false) |
| required | boolean | No | Whether a selection is required |
| error | boolean | No | Whether to show error styling |
| errorMessage | string | No | Error message to display when in error state |
| noOptionsMessage | string | No | Message when no options match search (default: “No options available”) |
| searchPlaceholder | string | No | Placeholder for search input (default: “Search…“) |
| className | string | No | Additional CSS classes for styling |
| onChange | function | No | Handler for value changes: (e: {target: {name, value}}) => void |
| value | string | No | Current selected value (controlled component) |
| name | string | No | Form field name |
| id | string | No | HTML ID attribute |
Features
- Search Functionality: Easily filter through options with the built-in search
- Keyboard Navigation: Full keyboard support for accessibility
- Form Integration: Works seamlessly in forms with proper value handling
- Customizable: Supports custom styling and placeholders
- Accessibility: ARIA attributes and keyboard interactions for accessibility compliance
Implementation Details
The Dropdown component is built using several supporting modules:
- useDropdown: Custom hook for managing dropdown state and behavior
- focusManagement: Utilities for keyboard focus handling
- keyboardNavigation: Support for keyboard interaction
- types: TypeScript type definitions
- utils: Helper functions
The component provides a robust implementation with consideration for accessibility, keyboard navigation, and user experience best practices.