WARNING: This component is in
Draft
status. This means that it is still in development and may have bugs or missing features. It is not intended to be used in production. You may use it for testing purposes.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,
};