Kanzo UI
Forms

Select

A listbox of options in a popover, driven by an Ark collection.

Ark UI

Usage

import {
  createListCollection,
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@kanzo-tech/ui";
const regions = createListCollection({
  items: [
    { label: "Thornmarch", value: "Thornmarch" },
    { label: "Duskfen", value: "Duskfen" },
  ],
});

The options live in a collection, not in the JSX. That is what lets the machine do type-ahead, keep the highlighted index across a re-render, and know an item's label without reading the DOM. createListCollection reads label and value off each item by default; override with itemToString / itemToValue for any other shape.

Build the collection once at module scope, or memoise it — a new collection on every render resets the machine.

Type-ahead is not filtering. Typing dus jumps the highlight to "Duskfen"; the list still shows every option. If you want the list to shrink as the user types, that is a Combobox.

Which of the choice controls this should be — and where the thresholds against NativeSelect and Combobox fall — is answered once, on Controls.

Anatomy

Two more ship and neither is in the tree. SelectClearTrigger is a button that empties the selection, for a select that is allowed to have no value. SelectContext is the render prop — a function instead of elements, rendering no element of its own, which is how a caller reads the selected items without useSelect().

Select
├── SelectTrigger          renders Control > Trigger + ClearTrigger
│   └── SelectValue
└── SelectContent
    ├── SelectGroup
    │   ├── SelectGroupLabel
    │   └── SelectItem
    ├── SelectSeparator
    └── SelectEmpty

With field

A writ needs a hall's seal and four signatures.

Groups

Give the collection a groupBy and collection.group() hands back the [heading, items] pairs, so the grouping is defined once with the data.

Multiple selection

multiple on the root, and the value becomes a list. SelectValue joins the selected labels for you, and each SelectItem grows a check indicator. You do not need a Combobox for this.

Clearable

Sizes

Disabled

Keyboard

KeyDoes
/ On the closed trigger, opens the list with the first / last option highlighted; inside, moves the highlight.
Alt+Opens the list with nothing highlighted.
Home / EndHighlights the first / last option once the list is open.
Enter / SpaceOpens the list from the trigger, and selects the highlighted option once it is open.
AZTypeahead: highlights the next option whose text starts with what you have typed.
EscCloses the list without changing the value and returns focus to the trigger.

On the closed trigger, /, Home/End and typeahead change the value outright without ever opening the list — single selection only, since there is no one value to step through under multiple.

API Reference

Select

PropTypeDefault
collectionListCollection
multiplebooleanfalse
lazyMountbooleantrue
unmountOnExitbooleantrue

Everything else passes through to Select.Rootvalue / defaultValue (always a string[], single or multiple), onValueChange, name, form, disabled, invalid, readOnly, positioning.

SelectTrigger

PropTypeDefault
size"sm" | "md" | "lg""md"
showClearbooleanfalse

Renders Select.Control and the chevron indicator for you.

SelectGroup

PropTypeDefault
headingstring | React.ReactNode

Select itself renders Select.HiddenSelect, so the value submits with a plain form, and defaults lazyMount / unmountOnExit to true.

On this page