Reticle@etched/reticle 0.0.0

Select

Pick one value (or several with multiple) from a list.

Kumo source
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

PropTypeDefaultDescription
level1 | 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–
disabledboolean–
classNamestring–

Select

PropTypeDefaultDescription
labelReactNode–
descriptionReactNode–
errorFieldError–
itemsReadonlyArray<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.
childrenReactNode–
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-labelstring–
placeholderReactNode–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).
classNamestring–Class on the trigger, for layout such as width.
sideBaseSelect.Positioner.Props["side"]"bottom"Which side of the trigger the list opens on.
alignBaseSelect.Positioner.Props["align"]"start"
alignItemWithTriggerbooleanfalseOverlay the list on the trigger like a native select.