Select

Select allows to create a dropdown list of options.

Source
Theme Source
pnpm dlx dreamy add select

Basic usage of Select.

<Select.Root>
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="strawberry">Strawberry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>

Select comes with 4 different sizes.

<Select.Root width="xs" size={"xs"}>
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="strawberry">Strawberry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>
<Select.Root width="xs" size={"sm"}>
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="strawberry">Strawberry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>
<Select.Root width="xs" size={"md"}>
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="strawberry">Strawberry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>
<Select.Root width="xs" size={"lg"}>
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="strawberry">Strawberry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>

Select can be used in outline or solid variant.

<Select.Root width="xs" variant={"outline"}>
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="strawberry">Strawberry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>
<Select.Root width="xs" variant={"solid"}>
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="strawberry">Strawberry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>

You can customize the background color of the selected item. This will only apply if selectedStrategy is set to both or background.

primary

success

warning

info

error

none

{["primary", "success", "warning", "info", "error", "none"].map((scheme) => (
    <>
        <Text>{scheme}</Text>
        <Select.Root width="xs" selectedItemBackgroundScheme={scheme} defaultValue="strawberry">
            <Select.Trigger placeholder="Select a favorite fruit" />
            <Select.Content>
                <Select.Item value="strawberry">Strawberry</Select.Item>
                <Select.Item value="banana">Banana</Select.Item>
                <Select.Item value="orange">Orange</Select.Item>
            </Select.Content>
        </Select.Root>
    </>
))}
export function ControlledSelect() {
    const [value, setValue] = useState<string>("strawberry");
 
    return (
        <Select.Root
            value={value}
            onChangeValue={setValue}
            width="xs"
        >
            <Select.Trigger
                placeholder="Select a favorite fruit"
            />
            <Select.Content>
                <Select.Item value="strawberry">Strawberry</Select.Item>
                <Select.Item value="banana">Banana</Select.Item>
                <Select.Item value="orange">Orange</Select.Item>
            </Select.Content>
        </Select.Root>
    );
}

You can customize how the selected value is marked as selected.

both

checkmark

background

<Wrapper>
    {["both", "checkmark", "background"].map((strategy) => (
        <>
            <Text>{strategy}</Text>
            <Select.Root
                key={strategy}
                selectedStrategy={strategy}
                width="xs"
            >
                <Select.Trigger placeholder="Select a favorite fruit" />
                <Select.Content>
                    <Select.Item value="strawberry">Strawberry</Select.Item>
                    <Select.Item value="banana">Banana</Select.Item>
                    <Select.Item value="orange">Orange</Select.Item>
                </Select.Content>
            </Select.Root>
        </>
    ))}
</Wrapper>

You can place icons, custom children in the Select.Item to indicate the type of the option.

<Select.Root width="xs">
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="cherry">
            <HStack>
                <LuCherry />
                <Text>Cherry</Text>
            </HStack>
        </Select.Item>
        <Select.Item value="banana">
            <HStack>
                <LuBanana />
                <Text>Banana</Text>
            </HStack>
        </Select.Item>
        <Select.Item value="orange">
            <HStack>
                <LuCitrus />
                <Text>Orange</Text>
            </HStack>
        </Select.Item>
    </Select.Content>
</Select.Root>

Single icon is useful if you want to have global icon for a trigger, instead of having it on each item.

<Select.Root width="xs">
    <Select.Trigger placeholder="Select a favorite fruit" icon={<LuCherry />} />
    <Select.Content>
        <Select.Item value="cherry">Cherry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>

Pass isClearable prop to enable clear button.

<Select.Root width="xs" isClearable>
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="cherry">Cherry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>

You can use the isMultiple prop to allow multiple selection. Now onChangeValue will return an array of values, instead of a single string value.

export function MultipleSelect() {
    return (
        <Select.Root width="xs" isMultiple>
            <Select.Trigger placeholder="Select a favorite fruit" />
            <Select.Content>
                <Select.Item value="strawberry">Strawberry</Select.Item>
                <Select.Item value="banana">Banana</Select.Item>
                <Select.Item value="orange">Orange</Select.Item>
            </Select.Content>
        </Select.Root>
    );
}

You can change the text that Select displays when multiple keys are selected by using multipleSelectedText prop in Select.Trigger.

export function MultipleSelect() {
    return (
        <Select.Root width="xs" isMultiple>
            <Select.Trigger
                placeholder="Select a favorite fruit"
                multipleSelectedText={(selectedKeys) => `${selectedKeys.join(", ")}`}
            />
            <Select.Content>
                <Select.Item value="strawberry">Strawberry</Select.Item>
                <Select.Item value="banana">Banana</Select.Item>
                <Select.Item value="orange">Orange</Select.Item>
            </Select.Content>
        </Select.Root>
    );
}

You can fetch data when the Select is opened.

export function AsyncSelect() {
    const [isLoading, setIsLoading] = useState(true);
    const [fruits, setFruits] = useState<string[]>([]);
 
    function fetchFruits() {
        if (fruits.length > 0) return;
 
        fetch("/api/fake-select-data") // slowed by 1 second
            .then((res) => res.json())
            .then(setFruits)
            .finally(() => setIsLoading(false));
    }
 
    return (
        <Select.Root width="xs" onOpen={fetchFruits}>
            <Select.Trigger placeholder="Select a favorite fruit" />
            <Select.Content>
                {isLoading && (
                    <Spinner
                        color="primary"
                        py={4}
                    />
                )}
                {fruits.map((fruit) => (
                    <Select.Item
                        key={fruit}
                        value={fruit}
                    >
                        {fruit}
                    </Select.Item>
                ))}
            </Select.Content>
        </Select.Root>
    );
}

For better performance with large lists (100+ items), use Select.VirtualContent instead of Select.Content. It only renders visible items, significantly improving rendering performance and reducing memory usage.

<Select.Root width="xs">
    <Select.Trigger placeholder="Select a number" />
    <Select.VirtualContent>
        {Array.from({ length: 250 }).map((_, index) => (
            <Select.Item
                key={index}
                value={index.toString()}
            >
                Item {index + 1}
            </Select.Item>
        ))}
    </Select.VirtualContent>
</Select.Root>

Props

  • estimatedItemHeight - Estimated height of each item in pixels. Used for virtualization calculations. For different select sizes the values will be: xs: 26, sm: 28, md: 32, lg: 40. Default: 32
  • overscan - Number of items to render outside the visible area. Higher values reduce flickering during fast scrolling but increase initial render cost. Default: 5
  • maxHeight - Maximum height of the virtualized list container in pixels. Default: 300
<Select.Root width="xs">
    <Select.Trigger placeholder="Select a number" />
    <Select.VirtualContent
        maxHeight={400}
        estimatedItemHeight={36}
        overscan={10}
    >
        {largeItemsList.map((item) => (
            <Select.Item
                key={item.value}
                value={item.value}
            >
                {item.label}
            </Select.Item>
        ))}
    </Select.VirtualContent>
</Select.Root>

Note: Selected items are always rendered (even when scrolled out of view) to ensure the trigger can display the selected value correctly.

You can customize whether the Select should close when an item is selected. Defalult is true for non-multiple select, false for multiple select.

<Select.Root width="xs" closeOnSelect={false}>
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="strawberry">Strawberry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>

You can disable the animation of the Select by setting the reduceMotion prop to true. You'll see no difference now if your device has currently reduced motion enabled globally.

<Select.Root width="xs" reduceMotion>
    <Select.Trigger placeholder="Select a favorite fruit" />
    <Select.Content>
        <Select.Item value="strawberry">Strawberry</Select.Item>
        <Select.Item value="banana">Banana</Select.Item>
        <Select.Item value="orange">Orange</Select.Item>
    </Select.Content>
</Select.Root>