Skip to content

Select

A focusable inline selection widget that cycles through one value from a list of options.

Usage

import { ui } from "@rezi-ui/core";

ui.select({
  id: "theme",
  value: state.theme,
  options: [
    { value: "dark", label: "Dark" },
    { value: "light", label: "Light" },
  ],
  onChange: (value) => app.update((s) => ({ ...s, theme: value })),
  placeholder: "Choose a theme…",
});

Props

Prop Type Default Description
id string required Unique identifier for focus and event routing
focusable boolean true Opt out of Tab focus while keeping id-based routing available
accessibleLabel string - Semantic label used for accessibility and focus announcements
value string required Currently selected value
options { value: string; label: string; disabled?: boolean }[] required Available options
onChange (value: string) => void - Called when selection changes
disabled boolean false Disable focus and interaction
placeholder string "Select..." Text shown when the current value has no matching option label
focusConfig FocusConfig - Control focus visuals; { indicator: "none" } suppresses focused select decoration
dsVariant "solid" \| "soft" \| "outline" \| "ghost" - Reserved for future select recipes (currently ignored)
dsTone "default" \| "primary" \| "danger" \| "success" \| "warning" - Reserved for future select recipes (currently ignored)
dsSize "sm" \| "md" \| "lg" "md" Design system size preset (controls padding)
key string - Reconciliation key

Design System Styling

Selects are design-system styled when semantic color tokens are available. dsSize is active today and affects recipe sizing. In SelectProps, dsVariant and dsTone are currently reserved for future select recipe variants and are ignored by the current select renderer.

If the active theme does not provide semantic color tokens, selects fall back to non-recipe rendering.

Note: like inputs, framed select chrome (border + interior) needs at least 3 rows of height. In a 1-row layout, the select still renders with recipe text/background styling, but without a box border.

Behavior

  • Focusable when enabled.
  • Mouse click focuses the select widget.
  • Navigate options with ArrowUp/ArrowDown.
  • Enter and Space advance to the next enabled option.
  • Tab / Shift+Tab moves focus to the next/previous widget.

This widget does not open a popup or dropdown list. It renders the current label inline and cycles through enabled options.

Examples

1) With a field wrapper

import { ui } from "@rezi-ui/core";

ui.field({
  label: "Theme",
  children: ui.select({
    id: "theme",
    value: state.theme,
    options: [
      { value: "dark", label: "Dark" },
      { value: "light", label: "Light" },
    ],
    onChange: (v) => app.update((s) => ({ ...s, theme: v })),
  }),
});

2) Disabled state

import { ui } from "@rezi-ui/core";

ui.select({
  id: "country",
  value: "us",
  options: [{ value: "us", label: "United States" }],
  disabled: true,
});