Select
Pick one value (or several with multiple) from a list.
import { Select } from "@etched/reticle/select";
const sites = [
{ value: "tpe-2", label: "TPE-2" },
{ value: "sjc-1", label: "SJC-1" },
{ value: "aus-3", label: "AUS-3 (offline)", disabled: true },
];
export function Preview() {
return <Select aria-label="Site" items={sites} placeholder="Choose a site" />;
}Installation
import { Select, SelectGroup, SelectGroupLabel, SelectOption, SelectSeparator } from "@etched/reticle/select";Examples
Basics
import { Select } from "@etched/reticle/select";
const statuses = { queued: "Queued", running: "Running", passed: "Passed", failed: "Failed" };
const sites = [
{ value: "tpe-2", label: "TPE-2" },
{ value: "sjc-1", label: "SJC-1" },
{ value: "aus-3", label: "AUS-3 (offline)", disabled: true },
];
export function Basics() {
return (
<div className="row">
<Select aria-label="Status" items={statuses} defaultValue="running" />
<Select aria-label="Site" items={sites} placeholder="Choose a site" />
<Select aria-label="Status, small" size="sm" items={statuses} defaultValue="passed" />
<Select aria-label="Status, disabled" items={statuses} defaultValue="queued" disabled />
</div>
);
}Pill (status in a table)
The trigger takes the color of the selected option's tone or hue.
import { Select } from "@etched/reticle/select";
const statuses = { queued: "Queued", running: "Running", passed: "Passed", failed: "Failed" };
const stages = [
{ value: "todo", label: "To Do", tone: "neutral" },
{ value: "scheduling", label: "Scheduling", tone: "orange" },
{ value: "scheduled", label: "Scheduled", tone: "purple" },
{ value: "touch", label: "In Touch", tone: "teal" },
{ value: "interviewing", label: "Interviewing", tone: "cyan" },
{ value: "references", label: "References check", tone: "cyan" },
{ value: "hired", label: "Hired", tone: "green" },
{ value: "passed", label: "We Passed", tone: "red" },
{ value: "trial", label: "Work trial (custom)", hue: 236 },
] as const;
export function PillStatusInATable() {
return (
<div className="row">
<Select aria-label="Stage" appearance="pill" items={stages} defaultValue="interviewing" />
<Select aria-label="Stage, hired" appearance="pill" items={stages} defaultValue="hired" />
<Select aria-label="Stage, custom" appearance="pill" items={stages} defaultValue="trial" />
<Select aria-label="Status, pill" appearance="pill" items={statuses} defaultValue="running" />
</div>
);
}In a form
Status
Runs in Failed state are retried at 02:00.
Site (optional)
Owner
Choose an owner before you save.
import { Select } from "@etched/reticle/select";
const statuses = { queued: "Queued", running: "Running", passed: "Passed", failed: "Failed" };
const sites = [
{ value: "tpe-2", label: "TPE-2" },
{ value: "sjc-1", label: "SJC-1" },
{ value: "aus-3", label: "AUS-3 (offline)", disabled: true },
];
export function InAForm() {
return (
<div className="grid">
<Select label="Status" items={statuses} defaultValue="running" description="Runs in Failed state are retried at 02:00." />
<Select label="Site" items={sites} placeholder="Choose a site" required={false} />
<Select label="Owner" items={{ ana: "Ana Ruiz", sam: "Sam Lee" }} placeholder="Choose an owner" error="Choose an owner before you save." />
</div>
);
}Groups and multiple
import { Select, SelectGroup, SelectGroupLabel, SelectOption, SelectSeparator } from "@etched/reticle/select";
const statuses = { queued: "Queued", running: "Running", passed: "Passed", failed: "Failed" };
export function GroupsAndMultiple() {
return (
<div className="row">
<Select aria-label="Bench" placeholder="Choose a bench">
<SelectGroup>
<SelectGroupLabel>Thermal</SelectGroupLabel>
<SelectOption value="b-14">B-14</SelectOption>
<SelectOption value="b-15">B-15</SelectOption>
</SelectGroup>
<SelectSeparator />
<SelectGroup>
<SelectGroupLabel>Power</SelectGroupLabel>
<SelectOption value="p-02">P-02</SelectOption>
</SelectGroup>
</Select>
<Select
aria-label="Statuses"
multiple
items={statuses}
defaultValue={["failed", "running"]}
placeholder="Any status"
// SAFETY: the items are the statuses record, so each value is one of its keys.
renderValue={(values) => (values.length === 1 ? statuses[values[0] as keyof typeof statuses] : `${values.length} statuses`)}
/>
</div>
);
}API reference
SelectOption
| Prop | Type | Default | Description |
|---|---|---|---|
| level | 1 | 2 | 3 | 4 | – | A step on the green ramp, for an ordinal score such as conviction 1–4. Wins over hue and tone. A Pill with a level is a small score box, and a list option with one takes the fill across its row. |
| value * | T | – | |
| children * | ReactNode | – | |
| disabled | boolean | – | |
| className | string | – |
Select
| Prop | Type | Default | Description |
|---|---|---|---|
| label | ReactNode | – | |
| description | ReactNode | – | |
| error | FieldError | – | |
| items | ReadonlyArray<SelectItem<T>> | ([T] extends [string] ? Record<string, ReactNode> : never) | – | Options as { label, value } objects; for string values, also a { value: label } record. Or pass SelectOption children. |
| children | ReactNode | – | |
| size | "sm" | "base" | "base" | Same heights as Input. |
| appearance | "default" | "pill" | "ghost" | "box" | "default" | pill is a rounded, borderless trigger for statuses in tables (Orbit\'s status dropdown). ghost has no edge or fill until hover, for values in table cells; it takes the selected option\'s ink. |
| aria-label | string | – | |
| placeholder | ReactNode | – | Shown in the trigger while nothing is selected. |
| renderValue | (value: Multiple extends true ? T[] : T) => ReactNode | – | Custom trigger text for the selected value (or values when multiple). |
| className | string | – | Class on the trigger, for layout such as width. |
| side | BaseSelect.Positioner.Props["side"] | "bottom" | Which side of the trigger the list opens on. |
| align | BaseSelect.Positioner.Props["align"] | "start" | |
| alignItemWithTrigger | boolean | false | Overlay the list on the trigger like a native select. |