Skip to main content

AmbientSelect

AmbientSelect is a bank of lamp-lit keys in a shared rail — the hardware idiom for a mode, bank or track selector, where the state is a lamp rather than a tick or a fill. Selecting a key lights the LED under it, and the light floods up through the key's translucent cap.

Interactive preview​

Bank
Accent

How it is built​

Each key is three physical layers, and the order is the whole trick:

  1. the option itself is the pocket floor, in the grounded amb-surface tone;
  2. amb-select-lens is the LED's lens — a big disc lying on that floor;
  3. amb-select-cap is a translucent diffuser sitting over both, carrying amb-mat-glass.

Because the cap is glass, its backdrop-filter blurs whatever is behind it — which is the lens. That single fact produces both states with no second gradient anywhere. Unlit, the lens body reads as a soft dark circle through the frost, so you can see the lamp is there. Lit, the same disc blooms into a broad radial glow with a hot centre, the way an LED actually behaves behind a diffuser. The light that escapes around the key onto the rail uses the grounded emissive bloom radius (6.2px, two sigma of the measured falloff — the same figure amb-glow uses).

Pressing a key sinks it and only sinks it, exactly as AmbientButton does: the drop shadow shortens and the chamfer bands narrow. Nothing repaints.

Multi-select​

Pass multiple to let several lamps be lit at once. The group's semantics change with it — single select is a radiogroup of radios where the arrow keys move focus and selection; multiple is a group of checkboxes where every key is tabbable and Space toggles the one you are on.

Tracks

Armed: A, C

Colour​

The lamp colour is --amb-led-color, the same variable amb-led and AmbientSwitch's led prop use — so one declaration lights every indicator on a panel. Set it per group with color, or per key with an option's own color. Left unset it falls back to the scene's --amb-highlight-color rather than to a hardcoded hue.

Orientation and sizes​

orientation="vertical" (the default) stacks the rail; "horizontal" lays it out as a row, and the arrow keys follow. size scales the key and its legend.

Keys are square by default — a bank of glyphs stays a bank of glyphs — but a longer legend is allowed to widen one: the size is a floor, not a fixed width. In a vertical rail every key then stretches to the widest, so the bank stays a bank. If you want uniform keys with long names, legend them with icons and put the names in ariaLabel.

Props​

PropTypeDefault
optionsAmbientSelectOption[]—
valuestring | string[]uncontrolled
defaultValuestring | string[]—
onChange(value: string | string[]) => void—
multiplebooleanfalse
orientation"vertical" | "horizontal""vertical"
size"sm" | "md" | "lg""md"
colorstring--amb-highlight-color
labelstring—

AmbientSelectOption is { value, label?, ariaLabel?, color?, disabled? }.

AmbientSelect is a preset over AmbientBank, whose parts apply per key rather than once. To change what a key looks like, pass keyParts — the lens has to sit in base and the cap in actuator, because the cap's backdrop-filter is what diffuses the lamp behind it. A key's parts can read their own option with useBankKey() and their own lit state from --ambx-percent or useControlState(). See Composing controls. label takes any node and falls back to value; ariaLabel supplies the accessible name and the hover title, and is needed whenever the legend is a glyph or an icon, which has no name of its own.

Also inherits all HTMLAttributes<HTMLDivElement> props.

Examples​

Controlled single select​

const [bank, setBank] = useState("3");

<AmbientSelect
label="Bank"
color="#00b4dc"
options={[{ value: "1" }, { value: "2" }, { value: "3" }, { value: "4" }]}
value={bank}
onChange={(next) => setBank(next as string)}
/>

Multi-select with a per-key colour​

<AmbientSelect
multiple
orientation="horizontal"
options={[
{ value: "A" },
{ value: "B", color: "#f59e0b" },
{ value: "C" },
{ value: "D", disabled: true }
]}
defaultValue={["A", "C"]}
/>