Dropdown
One option from a list, in a dropdown that searches, portals and reports the choice.
A dropdown asks for one value out of a set that is too long to keep on the page. What
separates it from a radio group is not the number of options but their cost, because the
list stays out of the way until it is asked for, and it can be searched, styled apart from
the trigger and rendered over the page's clipping. The trigger is a Button, so it takes
the button's variants, sizes and colours, and the field around it is the field family's
label, description and message.
Usage
import { Dropdown } from "@asheeui/web";
const speeds = [
{ label: "Standard", value: "standard" },
{ label: "Express", value: "express" },
];
<Dropdown
label="Delivery speed"
options={speeds}
value={speed}
onValueChange={setSpeed}
/>
Dropdown and Dropmenu are the same component. This page calls it a dropdown, and both
names import: the component was renamed from Select to Dropmenu in 1.0.0, and Dropdown
is the alias that matches what the documentation says. One thing keeps the original name:
the configuration section, components.dropmenu, because a key names the module rather than
the export. A theme written for either name configures the same trigger.
The trigger draws the label of the option whose value matches, so a set value is stated as
a name rather than as a code. onValueChange reports the value itself; onChange reports a
synthetic change event shaped like the browser's own <select>, for a form library that
listens for one. Pass whichever your state wants, or both.
placeholder is what the trigger says while no option matches, "Dropdown..." unless you
state otherwise. initialValue is the label shown when no option matches value, and it is
drawn as written rather than looked up among the options, so a real selection belongs in
value.
Search and the menu
isSearch puts a search field at the top of the menu, focused as the menu opens, and typing
filters the options by label. It is off unless you ask for it. An empty result is not a blank
panel: the menu states "No options found" in a status region, so the outcome is announced.
searchPlaceholder and searchInputName name the field, and belowList renders under the
options, an "Add new" action or a note about where the list comes from.
The menu is a component with its own tokens, and the menu prop overrides them one key at
a time: itemVariant and itemColor for options at rest, activeItemVariant and
activeItemColor for the selected one, radius and size for the options themselves. It
renders into a portal at the document body by default, so a dropdown inside a scrolling
table or a clipped panel is not cut off; menu={{ portal: false }} keeps it inside its
parent when a container needs to hold it. An option marked disabled stays in the list,
announces that it is unavailable and cannot be chosen.
Props
The trigger is a button, so it reads the field family's web defaults, size: "md" and
variant: "bordered", while radius is not registered: it follows the application's
defaultRadius, and color follows defaultColor. Stating either under
components.dropmenu pins it for every dropdown in the product.
The menu resolves its own tokens rather than borrowing the trigger's: itemVariant falls
back to ghost and activeItemVariant to faded, the two option colours fall back to
primary with the application's defaultColor in between, radius follows the
application's defaultRadius and then md, and size is md. portal and lockScroll
are both on. Write any of them under components.dropmenu.menu to change them once, or in
the menu prop to change them for one instance.
Accessibility
- The trigger is a real
<button type="button">witharia-haspopup="listbox"andaria-expanded, and the field's label names it. The description and the validation message are referenced witharia-describedby, and anerrorstatus setsaria-invalid. - The list is a
role="listbox"; each option is arole="option"witharia-selected, and a disabled option carriesaria-disabledand cannot be chosen. The checkmark beside the selected option is decoration on top of that state. - ↑ and ↓ on the trigger open the menu. Inside, the arrows move the current option and wrap, Home and End jump to the edges, typed characters jump to the first option whose label starts with them, and Escape closes the menu and returns focus to the trigger. Every one of those moves skips a disabled option.
- A search with no matches announces "No options found" through a
role="status"region, so an empty result is stated rather than left as a blank panel.
The label, description and message behave as the field anatomy describes.