ListBox
A run of selectable option rows sharing one native grouping name.
Arrow keys move the active row, Enter selects it, and typing jumps to a match.
View code
let value = "docs-site";
let activeValue: listbox.ListboxValue = "docs-site";
<listbox.Context
value={value}
activeValue={activeValue}
onSelect={(next) => {
value = next ?? value;
void handle.update();
}}
onHighlight={(next) => {
activeValue = next;
void handle.update();
}}
>
<div mix={[vstack({ gap: 2, align: "stretch" })]}>
<Header mix={[m(0)]}>Move issue to</Header>
<ListBox
role="listbox"
tabIndex={0}
aria-label="Move issue to"
name="projectId"
mix={[listboxKeys()]}
>
{GROUPS.map((group) => (
<Section key={group.id} aria-labelledby={group.id + "-heading"}>
<Header id={group.id + "-heading"}>{group.label}</Header>
{group.options.map((option) => (
<ListBox.Item
key={option.value}
value={option.value}
checked={value === option.value}
disabled={option.disabled}
mix={[listbox.option({ value: option.value, label: option.label, disabled: option.disabled })]}
>
{option.label}
</ListBox.Item>
))}
</Section>
))}
</ListBox>
<p mix={[m(0), text("xs")]}>
Arrow keys move the active row, Enter selects it, and typing jumps to a match.
</p>
</div>
</listbox.Context>Installation
An ordinary dependency: install it, import the theme once, and import the component where it is used.
npm add @sdxc/uiimport "@sdxc/ui/theme.css";Usage
import { ListBox } from "@sdxc/ui";Renders the group host: a <div> laying its ListBox.Item options
out as a scrollable column capped at a fixed block size, with role
defaulting to "radiogroup" for single selection or "group" for multiple.
Composition
The parts the component publishes, each a static property of the host.
ListBoxListBox.ItemRenders a single option: a native<label>pairing a visually hidden radio or checkbox input with the option's content.
Examples
<ListBox aria-label={t("settings.notifications")} multiple>
<Section aria-labelledby="notifications-heading">
<Header id="notifications-heading">{t("settings.channels")}</Header>
<ListBox.Item value="email" defaultChecked>{t("settings.email")}</ListBox.Item>
<ListBox.Item value="sms">{t("settings.sms")}</ListBox.Item>
</Section>
</ListBox>Props
Read from the component's own types, so every prop, every default and every allowed value is listed.
| Prop | Type | Description |
|---|---|---|
name? | string | Native grouping name shared by every ListBox.Item nested inside, provided through component context. Defaults to the group's own stable instance id, so options always group correctly. |
multiple? | boolean | Renders every option as a checkbox, allowing more than one selected at once, instead of the default mutually exclusive radio behavior. Defaults to DEFAULT_MULTIPLE. |
Also accepts everything in TagProps<"div">.
ListBox.Item
| Prop | Type | Description |
|---|---|---|
value | string | Value submitted with the enclosing form when this option is selected. |
name? | string | Native grouping name for this option's underlying input. Defaults to the name provided by the nearest ancestor ListBox — set this only to opt a single option out of its group's shared name. |
defaultChecked? | boolean | Whether this option starts selected, for a form that never tracks selection itself. |
checked? | boolean | Whether this option is selected, for a form that tracks selection itself. |
disabled? | boolean | Whether this option is inert and excluded from the group's tab order. |
required? | boolean | Sets the underlying input's native required attribute. On a radio input this requires at least one option in the group be selected; on a checkbox input it requires this specific option be checked. |
children? | RemixNode | The option's visible content, associated with the input by native nesting. |
parts? | {
/** Additional mixin(s) applied to the hidden native `<input>`. */
input?: TagProps<"input">["mix"];
} | Per-part styling for the option's hidden input element, layered after its own built-in styling. Use the mix prop instead to style the option's outer <label> host. |
Also accepts everything in Omit<TagProps<"label">, "children">.