Select

A dropdown to pick one option from a list. The list opens in a portal, so it is never clipped by a scrolling window body and stays above floating windows.

import { Select } from 'jarvis-react-ui';

Basic

Pass the options as options, each with a unique value and a label. placeholder is shown while nothing is selected; disabled options can't be picked.

import { Select } from 'jarvis-react-ui';

export default function Basic() {
    return (
        <Select
            aria-label="Voice"
            placeholder="Choose a voice…"
            options={[
                { value: 'jarvis', label: 'JARVIS' },
                { value: 'friday', label: 'FRIDAY' },
                { value: 'edith', label: 'EDITH' },
                { value: 'karen', label: 'KAREN', disabled: true },
            ]}
        />
    );
}

Controlled, with icons

Pass value and update it in onValueChange. icon shows content before the label, in the list and in the trigger.

import { useState } from 'react';
import { Globe, Moon, Sun } from 'lucide-react';
import { Select } from 'jarvis-react-ui';

export default function Controlled() {
    const [theme, setTheme] = useState('night');

    return (
        <div className="flex flex-col gap-3">
            <Select
                aria-label="Display mode"
                value={theme}
                onValueChange={setTheme}
                options={[
                    { value: 'night', label: 'Night', icon: <Moon size={12} /> },
                    { value: 'day', label: 'Day', icon: <Sun size={12} /> },
                    { value: 'auto', label: 'Follow location', icon: <Globe size={12} /> },
                ]}
            />
            <span className="text-[10px] text-text-secondary">Value: {theme}</span>
        </div>
    );
}

States

size="sm" for dense layouts, invalid for validation errors, disabled to lock it. With name the value is submitted with a surrounding <form>.

import { Select } from 'jarvis-react-ui';

const OPTIONS = [
    { value: 'a', label: 'Alpha' },
    { value: 'b', label: 'Bravo' },
];

export default function States() {
    return (
        <div className="flex flex-col gap-3">
            <Select aria-label="Small" size="sm" options={OPTIONS} defaultValue="a" />
            <Select aria-label="Invalid" invalid options={OPTIONS} />
            <Select aria-label="Disabled" disabled options={OPTIONS} defaultValue="b" />
        </div>
    );
}

Sound

Opening plays menu_open, closing menu_close and picking an option click; hovering the trigger plays hover_button. See Sound effects.

Accessibility

  • The trigger is a button with role="combobox", aria-haspopup="listbox", aria-expanded and aria-controls; name it with aria-label, aria-labelledby or a <label htmlFor={id}>.
  • ArrowDown, ArrowUp, Enter and Space open the list. In the list, the arrows move the active option (aria-activedescendant) and skip disabled ones, Home and End jump to the ends, typing letters jumps to a matching label, Enter or Space picks it, and Escape closes the list and returns focus to the trigger. Escape does not close a surrounding floating window.
  • A pointer down outside the list closes it.

API

Prop Type Default Description
options (required) SelectOption[] Options in display order.
aria-label string Accessible name of the trigger. Use it or aria-labelledby.
aria-labelledby string Id of an element that names the select.
className string Additional class names for the trigger button.
defaultValue string Initially selected value when uncontrolled.
disabled boolean false Disables the select.
fullWidth boolean false Stretches the trigger to the width of its container.
id string Id of the trigger button, e.g. for a <label htmlFor>.
invalid boolean false Marks the field as invalid: error border and aria-invalid.
name string Name for a hidden input, so the value is submitted with a surrounding <form>.
onValueChange ((value: string) => void) Called with the new value when the user picks an option.
placeholder string Select… Text shown in the trigger while nothing is selected.
size 'sm' | 'md' 'md' Height and font size of the trigger.
value string Controlled selected value. Leave undefined to use defaultValue.

Type SelectOption

One option of a Select.

Field Type Default Description
label (required) string Text shown in the list and, when selected, in the trigger. Also used for typeahead.
value (required) string Unique value of the option, reported through onValueChange.
disabled boolean false Disables the option.
icon ReactNode Icon or other content shown before the label.