Combobox
A filterable single-value picker on the ARIA combobox pattern.
import { Combobox, VStack } from "astralis-ui";
const FRAMEWORKS = [
{ label: "Next.js", value: "next" },
{ label: "Remix", value: "remix" },
{ label: "Astro", value: "astro" },
{ label: "Vite", value: "vite" },
{ label: "Gatsby", value: "gatsby", disabled: true },
];
const GROUPED = [
{ group: "Planets", options: [
{ label: "Mercury", value: "mercury" },
{ label: "Venus", value: "venus" },
{ label: "Mars", value: "mars" },
]},
{ group: "Moons", options: [
{ label: "Europa", value: "europa" },
{ label: "Titan", value: "titan" },
]},
];
export function ComboboxDemo() {
return (
<VStack gap="4" alignItems="stretch" w="full" maxW="sm">
<Combobox options={FRAMEWORKS} placeholder="Pick a framework…" clearable />
<Combobox options={GROUPED} placeholder="Grouped options…" defaultValue="europa" clearable />
</VStack>
);
}placeholder
emptyText
size
variant
colorScheme
name
import { Combobox } from "astralis-ui";
<Combobox
options={[
{ value: "react", label: "React" },
{ value: "vue", label: "Vue" },
{ value: "svelte", label: "Svelte" },
]}
/>
Import#
import { Combobox } from "astralis-ui";Type to filter, arrows to move, Enter to commit, Escape to revert to the last committed selection. Reopening on a committed value shows the full list. Filtering only kicks in once you type.
Compared to Select: Select is a button you pick
from; Combobox is an input you search in. For multiple values, use
MultiSelect. All three share the same
option machinery, so options shapes are interchangeable.
Free-form values#
By default the options are a closed set: text that matches nothing reverts on
blur. With allowCustomValue they become suggestions, and whatever the user
typed commits as the value on Tab, on blur, or on Enter when no option is
highlighted. Text that exactly matches an option's label commits that option,
and Escape still reverts.
import { Combobox } from "astralis-ui";
const LABELS = [
{ label: "bug", value: "bug" },
{ label: "design", value: "design" },
{ label: "docs", value: "docs" },
{ label: "performance", value: "performance" },
];
export function ComboboxCustomValue() {
return (
<Combobox
options={LABELS}
allowCustomValue
placeholder="Pick a label or type a new one…"
clearable
w="full"
maxW="sm"
/>
);
}Props#
| Prop | Type | Default | Description |
|---|---|---|---|
options | Array<{label, value, disabled?} | {group, options}> | [] | Flat or grouped options. |
value / defaultValue | string | number | null | None | Controlled / uncontrolled selection; null means nothing is selected. |
onChange | (value) => void | None | Fires on commit (pick or clear). |
onInputChange | (text) => void | None | Fires on every filter keystroke. |
placeholder | string | None | Input text shown while nothing is typed or selected. |
allowCustomValue | boolean | false | Typed text that matches no option commits as the value, so the options become suggestions. Tab, blur, or Enter with nothing highlighted commits; Escape reverts. |
clearable | boolean | false | ✕ button when a value is selected. |
emptyText | string | "No matches" | Shown when nothing matches. |
size | "sm" | "md" | "lg" | "md" | Field height and text size, matching Input. |
variant | "outline" | "filled" | "underline" | "unstyled" | "outline" | Field chrome, matching Input. |
colorScheme | all 15 schemes | "brand" | Hue for the focus ring and the highlighted option. |
loading | boolean | false | Shows a spinner and disables the input while options load. |
invalid | boolean | false | Error styling and aria-invalid. Inherited inside a Field. |
disabled | boolean | false | Blocks interaction. Inherited inside a Field. |
readOnly | boolean | false | Shows the value but can't be changed. |
name | string | None | Hidden input for native form submission. |
Keyboard#
| Key | Action |
|---|---|
| type | Filter the options |
↓ | Open when closed; move the highlight down |
↑ | Move the highlight up |
Enter | Commit the highlighted option |
Esc | Close and revert to the last committed value |
Tab | Close, revert, and move on |
Accessibility#
role="combobox" with aria-autocomplete="list", aria-expanded,
aria-controls and aria-activedescendant tracking the highlighted option:
the screen reader follows the highlight while focus stays in the input.
Label/description wiring comes from Field.