Dropdown
A select-like dropdown menu for choosing from a list of options.
Apple
Banana
Cherry
Grape
1<Dropdown><DropdownTrigger>...</DropdownTrigger><DropdownContent>...</DropdownContent></Dropdown>#Installation
1bunx barefoot add dropdown#Usage
1import { createSignal } from '@barefootjs/dom'2import {3 Dropdown,4 DropdownTrigger,5 DropdownContent,6 DropdownItem,7 DropdownLabel,8} from '@/components/ui/dropdown'910export default function Page() {11 const [open, setOpen] = createSignal(false)12 const [value, setValue] = createSignal('')1314 const options = [15 { value: 'apple', label: 'Apple' },16 { value: 'banana', label: 'Banana' },17 { value: 'cherry', label: 'Cherry' },18 ]1920 const selectedLabel = () => {21 const selected = options.find(opt => opt.value === value())22 return selected ? selected.label : ''23 }2425 const handleSelect = (optionValue: string) => {26 setValue(optionValue)27 setOpen(false)28 }2930 return (31 <Dropdown>32 <DropdownTrigger open={open()} onClick={() => setOpen(!open())}>33 {value() ? selectedLabel() : <DropdownLabel>Select...</DropdownLabel>}34 </DropdownTrigger>35 <DropdownContent open={open()} onClose={() => setOpen(false)}>36 {options.map(option => (37 <DropdownItem38 value={option.value}39 selected={value() === option.value}40 onClick={() => handleSelect(option.value)}41 >42 {option.label}43 </DropdownItem>44 ))}45 </DropdownContent>46 </Dropdown>47 )48}#Features
- Props-based state - Parent controls open/selected state with signals
- ESC key to close - Press Escape to close the dropdown
- Click to select - Click an item to select it
- Accessibility - role="combobox", role="listbox", role="option", aria-expanded, aria-selected
- Visual feedback - Selected item shows checkmark
#Examples
#Basic Dropdown
Apple
Banana
Cherry
Grape
1const [open, setOpen] = createSignal(false)2const [value, setValue] = createSignal('')34const options = [5 { value: 'apple', label: 'Apple' },6 { value: 'banana', label: 'Banana' },7 { value: 'cherry', label: 'Cherry' },8 { value: 'grape', label: 'Grape' },9]1011<Dropdown>12 <DropdownTrigger open={open()} onClick={() => setOpen(!open())}>13 {value() ? selectedLabel() : <DropdownLabel>Select a fruit</DropdownLabel>}14 </DropdownTrigger>15 <DropdownContent open={open()} onClose={() => setOpen(false)}>16 {options.map(option => (17 <DropdownItem18 value={option.value}19 selected={value() === option.value}20 onClick={() => handleSelect(option.value)}21 >22 {option.label}23 </DropdownItem>24 ))}25 </DropdownContent>26</Dropdown>#With Default Value
Small
Medium
Large
Extra Large
1const [open, setOpen] = createSignal(false)2const [value, setValue] = createSignal('medium') // Default value34const options = [5 { value: 'small', label: 'Small' },6 { value: 'medium', label: 'Medium' },7 { value: 'large', label: 'Large' },8 { value: 'xlarge', label: 'Extra Large' },9]1011<Dropdown>12 <DropdownTrigger open={open()} onClick={() => setOpen(!open())}>13 {selectedLabel()}14 </DropdownTrigger>15 <DropdownContent open={open()} onClose={() => setOpen(false)}>16 {options.map(option => (17 <DropdownItem18 value={option.value}19 selected={value() === option.value}20 onClick={() => handleSelect(option.value)}21 >22 {option.label}23 </DropdownItem>24 ))}25 </DropdownContent>26</Dropdown>#Disabled
Option 1
1<Dropdown>2 <DropdownTrigger open={open()} onClick={() => setOpen(!open())} disabled>3 <DropdownLabel>Disabled</DropdownLabel>4 </DropdownTrigger>5 <DropdownContent open={open()} onClose={() => setOpen(false)}>6 <DropdownItem value="option1" onClick={() => {}}>7 Option 18 </DropdownItem>9 </DropdownContent>10</Dropdown>#With CSS Transform
Dropdown inside a scaled container:
Option 1
Option 2
Option 3
Dropdown inside a rotated container:
Option 1
Option 2
Option 3
Dropdown inside a translated container:
Option 1
Option 2
Option 3
1// Dropdown works correctly inside CSS transformed containers2<div class="transform scale-100 translate-x-0">3 <Dropdown>4 <DropdownTrigger open={open()} onClick={() => setOpen(!open())}>5 {selectedLabel() || <DropdownLabel>Select option</DropdownLabel>}6 </DropdownTrigger>7 <DropdownContent open={open()} onClose={() => setOpen(false)}>8 <DropdownItem value="option1">Option 1</DropdownItem>9 <DropdownItem value="option2">Option 2</DropdownItem>10 </DropdownContent>11 </Dropdown>12</div>#Accessibility
- Keyboard Navigation - Arrow Up/Down to navigate, Home/End to jump, Enter/Space to select
- Focus Return - Focus returns to trigger after selection
- ESC to Close - Press Escape to close the dropdown
- ARIA - role="combobox" on trigger, role="listbox" on content, role="option" on items
- State Attributes - aria-expanded, aria-haspopup, aria-selected, aria-disabled
#API Reference
DropdownTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | false | Whether the dropdown is open. |
| disabled | boolean | false | Whether the trigger is disabled. |
| onClick | () => void | - | Event handler called when the trigger is clicked. |
DropdownContent
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | false | Whether the dropdown content is visible. |
| onClose | () => void | - | Event handler called when the dropdown should close (ESC key). |
DropdownItem
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | - | The value of the item. |
| selected | boolean | false | Whether the item is selected. |
| disabled | boolean | false | Whether the item is disabled. |
| onClick | () => void | - | Event handler called when the item is clicked. |
DropdownLabel
| Prop | Type | Default | Description |
|---|---|---|---|
| children | Child | - | The placeholder text to display. |