Combobox
Autocomplete input and command palette with a list of suggestions.
Apple
Apricot
Bilberry
Blackberry
Blackcurrant
Currant
Cherry
Coconut
import { component$ } from '@builder.io/qwik';
import { Combobox } from '~/components/ui';
import { LuCheck, LuChevronDown } from '@qwikest/icons/lucide';
export default component$(() => {
const fruits = [
'Apple',
'Apricot',
'Bilberry',
'Blackberry',
'Blackcurrant',
'Currant',
'Cherry',
'Coconut',
];
return (
<>
<Combobox.Root>
<Combobox.Label>Personal Trainers</Combobox.Label>
<Combobox.Control>
<Combobox.Input />
<Combobox.Trigger>
<LuChevronDown />
</Combobox.Trigger>
</Combobox.Control>
<Combobox.Popover gutter={8}>
{fruits.map((fruit) => (
<Combobox.Item key={fruit}>
<Combobox.ItemLabel>{fruit}</Combobox.ItemLabel>
<Combobox.ItemIndicator>
<LuCheck />
</Combobox.ItemIndicator>
</Combobox.Item>
))}
</Combobox.Popover>
</Combobox.Root>
</>
);
});
Installation
Run the following cli command or copy/paste the component code into your project
qwik-ui add combobox
import { type PropsOf, Slot, component$ } from '@builder.io/qwik';
import { Combobox as HeadlessCombobox } from '@qwik-ui/headless';
import { cn } from '@qwik-ui/utils';
import { LuChevronDown } from '@qwikest/icons/lucide';
const Root = (props: PropsOf<typeof HeadlessCombobox.Root>) => {
return (
<HeadlessCombobox.Root
{...props}
class={cn(
'flex h-full w-48 flex-col overflow-hidden bg-popover text-popover-foreground',
props.class,
)}
comboboxItemComponent={Item}
comboboxItemLabelComponent={ItemLabel}
>
{props.children}
</HeadlessCombobox.Root>
);
};
const Label = component$<PropsOf<typeof HeadlessCombobox.Label>>(({ ...props }) => {
return (
<HeadlessCombobox.Label {...props} class={cn('text-sm', props.class)}>
<Slot />
</HeadlessCombobox.Label>
);
});
const ItemLabel = component$<PropsOf<typeof HeadlessCombobox.ItemLabel>>(
({ ...props }) => {
return (
<HeadlessCombobox.ItemLabel {...props} class={cn('text-sm', props.class)}>
<Slot />
</HeadlessCombobox.ItemLabel>
);
},
);
const ItemIndicator = component$<PropsOf<typeof HeadlessCombobox.ItemIndicator>>(
({ ...props }) => {
return (
<HeadlessCombobox.ItemIndicator {...props} class={cn('text-sm', props.class)}>
<Slot />
</HeadlessCombobox.ItemIndicator>
);
},
);
const Control = component$<PropsOf<typeof HeadlessCombobox.Control>>((props) => {
return (
<HeadlessCombobox.Control
{...props}
class={cn('relative flex items-center rounded-base', props.class)}
>
<Slot />
</HeadlessCombobox.Control>
);
});
const Input = component$<PropsOf<typeof HeadlessCombobox.Input>>((props) => {
return (
<HeadlessCombobox.Input
{...props}
class={cn(
'flex h-10 w-full rounded-md border border-input py-3 pl-2 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
props.class,
)}
/>
);
});
const Trigger = component$<PropsOf<typeof HeadlessCombobox.Trigger>>(({ ...props }) => {
return (
<HeadlessCombobox.Trigger
{...props}
class={cn('group absolute right-0 h-6 w-6', props.class)}
>
<LuChevronDown class="stroke-foreground transition-transform duration-500 group-aria-expanded:-rotate-180" />
</HeadlessCombobox.Trigger>
);
});
const Popover = component$<PropsOf<typeof HeadlessCombobox.Popover>>((props) => {
return (
<HeadlessCombobox.Popover
{...props}
class={cn('w-48 rounded-base border p-2', props.class)}
>
<Slot />
</HeadlessCombobox.Popover>
);
});
const Item = component$<PropsOf<typeof HeadlessCombobox.Item>>(({ ...props }) => {
return (
<HeadlessCombobox.Item
{...props}
class={cn(
'group flex justify-between gap-4 rounded-sm px-2 text-foreground aria-disabled:font-light aria-disabled:text-muted-foreground data-[highlighted]:cursor-pointer data-[highlighted]:bg-accent',
props.class,
)}
>
<Slot />
</HeadlessCombobox.Item>
);
});
export const Combobox = {
Root,
Label,
Control,
Input,
Trigger,
Popover,
Item,
ItemLabel,
ItemIndicator,
};