Select
A custom dropdown with search, groups, clearing, and full keyboard navigation.
"use client";
import { useState } from "react";
import { Select, Box } from "astralis-ui";
const options = [
{ value: "figma", label: "Figma" },
{ value: "sketch", label: "Sketch" },
{ value: "penpot", label: "Penpot" },
];
export function SelectDemo() {
const [tool, setTool] = useState<string | number | null>(null);
return (
<Box w="full" maxW="3xs">
<Select
options={options}
value={tool}
onChange={setTool}
placeholder="Pick a design tool"
/>
</Box>
);
}Import#
import { Select } from "astralis-ui";Usage#
Options come in as data — flat { value, label } items or
{ group, options } sections — and the dropdown portals out of any
overflow: hidden ancestor, so it works inside cards and modals.
Searchable, clearable, grouped#
"use client";
import { Select, Box } from "astralis-ui";
const options = [
{
group: "Frontend",
options: [
{ value: "react", label: "React" },
{ value: "vue", label: "Vue" },
{ value: "svelte", label: "Svelte" },
],
},
{
group: "Backend",
options: [
{ value: "node", label: "Node.js" },
{ value: "elixir", label: "Elixir" },
{ value: "go", label: "Go" },
],
},
];
export function SelectSearchable() {
return (
<Box w="full" maxW="3xs">
<Select
options={options}
searchable
clearable
placeholder="Search frameworks…"
/>
</Box>
);
}States#
filled variant
loading
invalid
disabled
"use client";
import { Select, Text, VStack } from "astralis-ui";
const options = [{ value: "one", label: "Option one" }];
export function SelectStates() {
return (
<VStack gap="4" alignItems="stretch" w="full" maxW="3xs">
<VStack gap="1" alignItems="stretch">
<Text as="span" size="xs" color="muted">filled variant</Text>
<Select options={options} variant="filled" placeholder="Filled" />
</VStack>
<VStack gap="1" alignItems="stretch">
<Text as="span" size="xs" color="muted">loading</Text>
<Select options={[]} loading placeholder="Fetching options…" />
</VStack>
<VStack gap="1" alignItems="stretch">
<Text as="span" size="xs" color="muted">invalid</Text>
<Select options={options} invalid placeholder="Required field" />
</VStack>
<VStack gap="1" alignItems="stretch">
<Text as="span" size="xs" color="muted">disabled</Text>
<Select options={options} disabled placeholder="Unavailable" />
</VStack>
</VStack>
);
}Props#
| Prop | Type | Default | Description |
|---|---|---|---|
options | { value, label }[] or { group, options }[] | [] | The option data. |
value / defaultValue / onChange | string | number | null / same / (value) => void | — / null / — | Controlled / uncontrolled API. |
placeholder | string | "Select an option" | Trigger text when empty. |
searchable | boolean | false | Filter input inside the dropdown. |
clearable | boolean | false | × button when a value is selected (also fires onClear). |
loading | boolean | false | Spinner instead of the chevron. |
emptyText | string | "No options" | Shown when nothing matches. |
name | string | — | Renders a hidden input so the value submits with native <form>s. |
variant / size | "outline" | "filled" / "sm" | "md" | "lg" | "outline" / "md" | Styling. |
colorScheme | all 11 schemes | "brand" | Highlight and focus-ring hue. |
invalid / disabled / readOnly | boolean | false | State flags — inherited from Field. |
Keyboard#
| Key | Action |
|---|---|
Enter / Space | Open; when open, select the highlighted option |
↓ | Open when closed; move the highlight down |
↑ | Move the highlight up |
type (with searchable) | Filter the options |
Esc | Close and refocus the trigger |
Tab | Close and move on |
Accessibility#
- The trigger is a
comboboxwitharia-haspopup="listbox"andaria-expanded; options carryrole="option". - Selecting an option returns focus to the trigger.