remix/ui/listbox · DemoView Source
Listbox Overview
A keyboard-navigable listbox with selection, highlighting, and an optional flash-selection animation.
Apple
Banana
Cherry
Date
Elderberry
Fig
Grape
value=apple
import { css, on, type Handle } from 'remix/ui'
import { Glyph } from 'remix/ui/glyph'
import * as listbox from 'remix/ui/listbox'
import type { ListboxValue } from 'remix/ui/listbox'
import { theme } from 'remix/ui/theme'
export default function Example(handle: Handle) {
let value: ListboxValue = options[0]!.value
let activeValue: ListboxValue = options[0]!.value
let flashSelection = false
return () => {
return (
<div mix={stackCss}>
<listbox.Context
value={value}
activeValue={activeValue}
flashSelection={flashSelection}
onSelect={(nextValue) => {
value = nextValue
handle.update()
}}
onHighlight={(nextActiveValue) => {
activeValue = nextActiveValue
handle.update()
}}
>
<div
tabIndex={0}
mix={[listbox.listStyle, listbox.list(), containerCss]}
>
{options.map((option) => (
<div
key={option.value}
mix={[listbox.optionStyle, listbox.option(option)]}
>
<Glyph mix={listbox.glyphStyle} name="check" />
<span mix={listbox.labelStyle}>{option.label}</span>
</div>
))}
</div>
</listbox.Context>
<div mix={controlsCss}>
<label mix={checkboxLabelCss}>
<input
type="checkbox"
defaultChecked={flashSelection}
mix={on('change', (event) => {
flashSelection = event.currentTarget.checked
handle.update()
})}
/>{' '}
Flash selection
</label>
<p mix={valueCss}>{`value=${value ?? 'null'}`}</p>
</div>
</div>
)
}
}
const options = [
{ label: 'Apple', value: 'apple' },
{ label: 'Banana', value: 'banana' },
{ label: 'Cherry', value: 'cherry' },
{ label: 'Date', value: 'date' },
{ label: 'Elderberry', value: 'elderberry' },
{ label: 'Fig', value: 'fig' },
{ label: 'Grape', value: 'grape' },
] as const
const containerCss = css({
borderColor: theme.colors.border.subtle,
padding: theme.space.xs,
borderRadius: theme.radius.lg,
borderStyle: 'solid',
})
const stackCss = css({
display: 'flex',
flexDirection: 'column',
gap: theme.space.md,
width: '100%',
})
const controlsCss = css({
display: 'flex',
flexDirection: 'column',
gap: theme.space.xs,
})
const checkboxLabelCss = css({
fontSize: theme.fontSize.sm,
lineHeight: theme.lineHeight.normal,
color: theme.colors.text.secondary,
})
const valueCss = css({
margin: 0,
fontFamily: theme.fontFamily.mono,
fontSize: theme.fontSize.xs,
color: theme.colors.text.secondary,
})