KQ-1500 · RAIL/SELECT

Rail Select

A select whose open list has a rail down its side with a node per option, like a line on a transit map, and whose highlight is one shape — a wash across the row and a car on the rail — with its top and bottom edges on separate springs: the leading edge leaves on a stiff spring and the trailing edge follows on a softer, later one, so the highlight stretches toward the next stop before its tail catches up. Choosing rolls the trigger's value to the new label on springs.snap, out the way the list moved, while the rail draws down on springs.glide each time the list opens. It is an APG select-only combobox: focus stays on the trigger while arrows, Home, End, Page keys and type-ahead move the highlight, Enter, Space or Tab choose, and Escape closes.

KQ-1500 · RAIL/SELECT
Edge region
Latency
18 ms
Failover
Fjord North
Data stays in
Harbor
Cache
Warm

region · harbor east · 18 ms

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/rail-select

Props

options
{ value: string; label: string; hint?: string; disabled?: boolean }[]
default —
The stops on the rail, top to bottom; a hint sits at the row's end, and disabled options are skipped by every key.
value / defaultValue
string | null
default — / null
The chosen option's value, controlled or uncontrolled.
onValueChange
(value: string) => void
default —
Fires from the click or key that chose an option.
open / defaultOpen
boolean
default — / false
Whether the list is open, controlled or uncontrolled.
onOpenChange
(open: boolean) => void
default —
Fires from the press, key or outside press that opened or closed it.
label
string
default —
What is being chosen: the caption above the trigger and the list's accessible name.
hideLabel
boolean
default false
Keep the caption for assistive technology only.
placeholder
string
default "Choose"
The trigger's text before anything is chosen.
stretch
number
default 0.5
How far the highlight stretches toward the next option before its tail catches up, 0 to 1: the trailing edge's spring softens and lags as it rises.
speed
number
default 0.5
How quick the ride is, 0 to 1: the leading edge's stiffness, from a heavy car to a light one.
width
number
default 240
The trigger's and the list's width in px, never wider than the container.
side
"bottom" | "top"
default "bottom"
Which way the list opens from the trigger.
color
string
default "var(--accent-bright)"
The car, the wash (mixed at 13% in oklab) and the chosen node. Any CSS colour.
railColor
string
default "var(--hairline-strong)"
The rail and its nodes. Any CSS colour.
name
string
default —
Submits the value with a form under this name, through a hidden input.
size
"sm" | "md" | "lg"
default "md"
Trigger height 32, 36 or 40px and row height 28, 32 or 36px.
sound
boolean
default false
Play a tick as the highlight moves, pitched by its place on the rail, and a lower one on a choice.
disabled
boolean
default false
Disables the trigger and keeps the list shut.
className
string
default —
Classes for the root column (caption, trigger and list).