Tinyrack

Select

Chooses one value from a known collection and exposes a button-triggered, keyboard-navigable popup.

Contract

AxisBehavior
valueuncontrolled with defaultValue, controlled with value and onValueChange
openuncontrolled with defaultOpen, controlled with open and onOpenChange
disclosureTrigger owns focus; Portal, Positioner, and Popup own the floating layer
popup geometrypopup width is at least the trigger width and normally 256 px, capped at 320 px and the available viewport; option padding fills each highlighted row
collectiongroups, labels, separators, disabled items, text, and indicators describe the menu anatomy
formsname, form, required, and inputRef integrate with native submission, validation, and reset

Use TRSelect.Trigger uiSize="md" when the trigger belongs to a dense control surface.

Install

pnpm add @tinyrack/ui

Scroll inside the code area to read long lines.

Styles

@import '@tinyrack/ui/components/select.css';

Scroll inside the code area to read long lines.

Imports

import { TRSelect } from '@tinyrack/ui/components/select';
import { TRForm } from '@tinyrack/ui/components/form';
import { TRField } from '@tinyrack/ui/components/field';
import { TRButton } from '@tinyrack/ui/components/button';
import { ChevronDown } from 'lucide-react';

Scroll inside the code area to read long lines.

Playground

Usage

Examples

Trigger sizes permalink

Choose the trigger density independently from the popup collection.

Long scrolling collection permalink

Open the popup to verify constrained height, scroll arrows, long labels, and highlighted focus treatment.

API

The complete anatomy is Root, Label, Trigger, Value, Icon, Portal, Backdrop, Positioner, Popup, List, Item, ItemIndicator, ItemText, Arrow, ScrollDownArrow, ScrollUpArrow, Group, GroupLabel, and Separator. Every part is available as both TRSelect.Part and a named TRSelectPart export, with matching TRSelectPartProps and TRSelectPartState types.

PurposePublic props and defaults
valuedefaultValue or controlled value; multiple={false} by default; items maps values to displayed labels
disclosuredefaultOpen={false} or controlled open; modal={true} and highlightItemOnHover={true} by default
availabilitydisabled={false}, readOnly={false}, and required={false}
trigger`uiSize="md"
positioningPositioner opens 4 px below the trigger and does not accept placement props; it flips above when the available space requires it
formsname, form, autoComplete, and inputRef; uncontrolled selects restore defaultValue on native reset

Give Trigger an accessible name. Keyboard users can open with Arrow Down, move through enabled options, use typeahead, confirm with Enter, and dismiss with Escape while focus returns to the trigger. Pointer hover, open, highlighted, and selected states use background emphasis only; the focus border appears only for keyboard-origin focus. Keep value and open controlled independently when needed. Use disabled for unavailable controls and readOnly for focusable values that cannot change.