ComboboxPopover

Use a ref-forwarding child inside Target. On phones the list opens in a centered dialog.

Basics

Attach an option list to any ref-forwarding trigger. Search filters labels.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; export function Demo() { return ( <ComboboxPopover data={['Apple', 'Banana', 'Cherry', 'Date']} searchable> <ComboboxPopover.Target> <Button>Select fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Multiple Selection

multiple keeps the list open while options are toggled.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; export function Demo() { return ( <ComboboxPopover data={data} multiple defaultValue={['Apple']}> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Disabled Options

Disabled entries stay visible and are skipped by selection.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = [{ value: 'Apple' }, { value: 'Banana', disabled: true }, { value: 'Cherry' }]; export function Demo() { return ( <ComboboxPopover data={data}> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Groups

Group headings organize related options.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = [ { group: 'Fruit', items: ['Apple', 'Banana'] }, { group: 'Vegetables', items: ['Carrot', 'Pea'] }, ]; export function Demo() { return ( <ComboboxPopover data={data}> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Searchable

Typing filters options by their labels.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; export function Demo() { return ( <ComboboxPopover data={data} searchable> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Custom Sort

filter can sort the parsed options after filtering.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; export function Demo() { return ( <ComboboxPopover data={data} searchable filter={({ options }) => [...options].reverse()}> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Limit Results

limit caps the number of matching options.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; export function Demo() { return ( <ComboboxPopover data={data} searchable limit={3}> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Nothing Found

Show a message when no options match the search.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; export function Demo() { return ( <ComboboxPopover data={data} searchable nothingFoundMessage="No fruit matches"> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Check Icon Position

Move the selected check mark to the end of each row.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; export function Demo() { return ( <ComboboxPopover data={data} defaultValue="Apple" checkIconPosition="end" withAlignedLabels> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Disallow Deselect

allowDeselect={false} keeps a selected option selected on a second press.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; export function Demo() { return ( <ComboboxPopover data={data} defaultValue="Apple" allowDeselect={false}> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Custom Option

renderOption replaces row content while retaining option semantics.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; export function Demo() { return ( <ComboboxPopover data={data} renderOption={({ option }) => option.label.toUpperCase()}> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }
position chooses the side of the target.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; export function Demo() { return ( <ComboboxPopover data={data} position="top-start"> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }
Use a numeric dropdownWidth instead of matching the target.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']; export function Demo() { return ( <ComboboxPopover data={data} dropdownWidth={320}> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Large Data

The dropdown scrolls when the data exceeds its height.

Loading demo…

import { Button, ComboboxPopover } from '@plocks/ui'; const data = Array.from({ length: 100 }, (_, index) => `Option ${index + 1}`); export function Demo() { return ( <ComboboxPopover data={data} maxDropdownHeight={180}> <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }

Controlled Dropdown

dropdownOpened lets the parent own open state.

Loading demo…

import { useState } from 'react'; import { Button, ComboboxPopover } from '@plocks/ui'; export function Demo() { const [opened, setOpened] = useState(false); return ( <ComboboxPopover data={['Apple', 'Banana']} dropdownOpened={opened} onDropdownOpen={() => setOpened(true)} onDropdownClose={() => setOpened(false)} > <ComboboxPopover.Target> <Button>Choose fruit</Button> </ComboboxPopover.Target> </ComboboxPopover> ); }
Scan to open this page on your phoneplocks.dev/ui/ComboboxPopover