Select
A form-aware menu for selecting one option, with keyboard navigation and typeahead.
Installation
Import from the Reflow workspace package.
Playground
Open demoimport { Select } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
return () => (
<>
<Select label="Role" name="role" options={[
{ value: 'viewer', label: 'Viewer' },
{ value: 'editor', label: 'Editor' },
]} defaultValue="viewer" />
</>
)
}Variants
import { Select } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({
value: label.toLowerCase(), label,
}))
return () => (
<>
<Select label="Bordered" options={options} variant="bordered" />
<Select label="Ghost" options={options} variant="ghost" />
</>
)
}With Icons
import { Select } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({
value: label.toLowerCase(), label,
}))
const icon = <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M4 6h16M4 12h16M4 18h16" /></svg>
return () => (
<>
<Select label="Fruit" options={options.map(option => ({ ...option, icon }))} />
</>
)
}Groups
import { Select } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
return () => (
<>
<Select label="Settings" placeholder="Settings…" options={[
{ value: 'profile', label: 'Profile', group: 'Account' },
{ value: 'email', label: 'Email', group: 'Account' },
{ value: 'notifications', label: 'Notifications', group: 'Preferences' },
{ value: 'privacy', label: 'Privacy', group: 'Preferences' },
]} />
</>
)
}Scrollable List
import { Select } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
const timezones = Intl.supportedValuesOf('timeZone').map((label) => ({ value: label, label }))
return () => (
<>
<Select label="Timezone" options={timezones} />
</>
)
}Error State
import { Field, Select } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
let plan = 'free'
const select = (value: string) => { plan = value; handle.update() }
return () => (
<>
<Field label="Role" error="Please select a role to continue.">
{(control) => <Select {...control} label="Role" placeholder="Select a role…" options={roles} />}
</Field>
</>
)
}Disabled
import { Select } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({
value: label.toLowerCase(), label,
}))
return () => (
<>
<Select label="Fruit" options={options} defaultValue="apple" disabled />
</>
)
}API Reference
Public props for the Reflow implementation. Native controls also accept their standard HTML attributes and Remix event mixes.
Select
| Prop | Type | Default | Description |
|---|---|---|---|
label* | string | — | Accessible name or visible label for the control. |
options* | readonly ChoiceOption[] | — | Choices available to the user. |
name | string | — | Name used when the control participates in a form. |
defaultValue | string | — | Initial value for an uncontrolled component. |
value | string | null | — | Current value when controlled by the parent. |
onValueChange | ((value: string | null) => void) | — | Called when the selected value changes. |
disabled | boolean | — | Prevents interaction and conveys the disabled state. |
placeholder | string | Choose an option… | Hint shown while the value is empty. |
variant | "ghost" | "bordered" | bordered | Visual or layout treatment. |
size | "default" | "compact" | — | Control density or icon-button dimensions. |
ChoiceOption
| Prop | Type | Default | Description |
|---|---|---|---|
value* | string | — | Value submitted when this option is selected. |
label* | string | — | Text shown for the option. |
icon | RemixNode | — | Icon content. |
disabled | boolean | — | Prevents interaction and conveys the disabled state. |
searchValue | string | string[] | — | Additional text matched by filtering or typeahead. |