Zaidan

Command Palette

Search for a command to run...

GitHub

Combobox

Autocomplete input and command palette with a list of suggestions.

Installation

CLI

Manual

Copy and paste the following code into your project.

import type {
ComboboxContentProps as ComboboxPrimitiveContentProps,
ComboboxControlProps as ComboboxPrimitiveControlProps,
ComboboxInputProps as ComboboxPrimitiveInputProps,
ComboboxItemProps as ComboboxPrimitiveItemProps,
ComboboxSectionProps as ComboboxPrimitiveSectionProps,
ComboboxTriggerProps as ComboboxPrimitiveTriggerProps,
ComboboxRootProps,
} from "@kobalte/core/combobox";
import * as ComboboxPrimitive from "@kobalte/core/combobox";
import type { PolymorphicProps } from "@kobalte/core/polymorphic";
import { Check, ChevronsUpDown, X } from "lucide-solid";
import type { ComponentProps, JSX, ValidComponent } from "solid-js";
import { mergeProps, Show, splitProps } from "solid-js";
import { cn } from "~/lib/utils";
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
} from "~/components/ui/input-group";
// ============================================================================
// Combobox Root
// ============================================================================
type ComboboxProps<O, OptGroup = never, T extends ValidComponent = "div"> = PolymorphicProps<
T,
ComboboxRootProps<O, OptGroup, T>
> &
Pick<ComponentProps<T>, "class" | "children">;
const Combobox = <O, OptGroup = never, T extends ValidComponent = "div">(
props: ComboboxProps<O, OptGroup, T>,
) => {
const mergedProps = mergeProps(
{
sameWidth: true,
gutter: 8,
placement: "bottom",
defaultFilter: "contains",
triggerMode: "input",
} as ComboboxProps<O>,
props,
);
return <ComboboxPrimitive.Root {...mergedProps} />;
};
// ============================================================================
// Combobox Control
// ============================================================================
type ComboboxControlProps<T extends ValidComponent = "div"> = PolymorphicProps<
T,
ComboboxPrimitiveControlProps<T>
> &
Pick<ComponentProps<T>, "class" | "children">;
const ComboboxControl = <T extends ValidComponent = "div">(props: ComboboxControlProps<T>) => {
const [local, others] = splitProps(props as ComboboxControlProps, ["class"]);
return (
<ComboboxPrimitive.Control
class={cn("z-combobox-control", local.class)}
data-slot="combobox-control"
{...others}
/>
);
};
// ============================================================================
// Combobox Input
// ============================================================================
type ComboboxInputProps<T extends ValidComponent = "input"> = PolymorphicProps<
T,
ComboboxPrimitiveInputProps<T>
> &
Pick<ComponentProps<"input">, "class" | "placeholder" | "disabled" | "id" | "name"> & {
showTrigger?: boolean;
showClear?: boolean;
children?: JSX.Element;
};
const ComboboxInput = <T extends ValidComponent = "input">(rawProps: ComboboxInputProps<T>) => {
const props = mergeProps({ showTrigger: true, showClear: false }, rawProps);
const [local, others] = splitProps(props as ComboboxInputProps, [
"class",
"showTrigger",
"showClear",
"children",
"disabled",
]);
return (
<ComboboxPrimitive.Control
as={InputGroup}
class={cn("z-combobox-input w-auto", local.class)}
data-slot="combobox-control"
>
{(state) => (
<>
{local.children}
<ComboboxPrimitive.Input
as={InputGroupInput}
disabled={local.disabled}
data-slot="combobox-input"
{...others}
/>
<InputGroupAddon align="inline-end">
<Show when={local.showTrigger}>
<ComboboxPrimitive.Trigger
as={InputGroupButton}
size="icon-xs"
variant="ghost"
data-slot="combobox-trigger"
class="group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent"
disabled={local.disabled}
>
<ComboboxPrimitive.Icon
as={ChevronsUpDown}
class="pointer-events-none z-combobox-trigger-icon"
/>
</ComboboxPrimitive.Trigger>
</Show>
<Show when={local.showClear && state.selectedOptions().length > 0}>
<InputGroupButton
variant="ghost"
size="icon-xs"
data-slot="combobox-clear"
class="z-combobox-clear"
disabled={local.disabled}
onClick={() => state.clear()}
>
<X class="pointer-events-none z-combobox-clear-icon" />
</InputGroupButton>
</Show>
</InputGroupAddon>
</>
)}
</ComboboxPrimitive.Control>
);
};
// ============================================================================
// Combobox Trigger (for popup-style combobox)
// ============================================================================
type ComboboxTriggerProps<T extends ValidComponent = "button"> = PolymorphicProps<
T,
ComboboxPrimitiveTriggerProps<T>
> &
Pick<ComponentProps<T>, "class" | "children"> & {
size?: "sm" | "default";
};
const ComboboxTrigger = <T extends ValidComponent = "button">(
rawProps: ComboboxTriggerProps<T>,
) => {
const props = mergeProps({ size: "default" }, rawProps);
const [local, others] = splitProps(props as ComboboxTriggerProps, ["class", "children", "size"]);
return (
<ComboboxPrimitive.Control>
<ComboboxPrimitive.Trigger
class={cn(
"z-combobox-trigger z-select-trigger flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=combobox-value]:line-clamp-1 *:data-[slot=combobox-value]:flex *:data-[slot=combobox-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
local.class,
)}
data-size={local.size}
data-slot="combobox-trigger"
{...others}
>
{local.children}
<ComboboxPrimitive.Icon
as={ChevronsUpDown}
class="pointer-events-none z-combobox-trigger-icon"
/>
</ComboboxPrimitive.Trigger>
</ComboboxPrimitive.Control>
);
};
// ============================================================================
// Combobox Content
// ============================================================================
type ComboboxContentProps<T extends ValidComponent = "div"> = PolymorphicProps<
T,
ComboboxPrimitiveContentProps<T>
> &
Pick<ComponentProps<T>, "class">;
const ComboboxContent = <T extends ValidComponent = "div">(props: ComboboxContentProps<T>) => {
const [local, others] = splitProps(props as ComboboxContentProps, ["class"]);
return (
<ComboboxPrimitive.Portal>
<ComboboxPrimitive.Content
class={cn(
"relative isolate z-50 z-combobox-content z-menu-target max-h-(--kb-popper-available-height) min-w-32 origin-(--kb-combobox-content-transform-origin) overflow-y-auto overflow-x-hidden",
local.class,
)}
data-slot="combobox-content"
{...others}
>
<ComboboxPrimitive.Listbox class="z-combobox-listbox m-0 p-1" />
</ComboboxPrimitive.Content>
</ComboboxPrimitive.Portal>
);
};
// ============================================================================
// Combobox Section (Group)
// ============================================================================
type ComboboxSectionProps<T extends ValidComponent = "li"> = PolymorphicProps<
T,
ComboboxPrimitiveSectionProps<T>
> &
Pick<ComponentProps<T>, "class">;
const ComboboxSection = <T extends ValidComponent = "li">(props: ComboboxSectionProps<T>) => {
const [local, others] = splitProps(props as ComboboxSectionProps, ["class"]);
return (
<ComboboxPrimitive.Section
class={cn("z-combobox-section", local.class)}
data-slot="combobox-section"
{...others}
/>
);
};
// ============================================================================
// Combobox Section Label
// ============================================================================
type ComboboxSectionLabelProps = ComponentProps<"span"> & {
class?: string;
};
const ComboboxSectionLabel = (props: ComboboxSectionLabelProps) => {
const [local, others] = splitProps(props, ["class"]);
return (
<span
class={cn("z-combobox-section-label z-select-label", local.class)}
data-slot="combobox-section-label"
{...others}
/>
);
};
// ============================================================================
// Combobox Item
// ============================================================================
type ComboboxItemProps<T extends ValidComponent = "li"> = PolymorphicProps<
T,
ComboboxPrimitiveItemProps<T>
> &
Pick<ComponentProps<T>, "class"> & {
children?: JSX.Element;
};
const ComboboxItem = <T extends ValidComponent = "li">(props: ComboboxItemProps<T>) => {
const [local, others] = splitProps(props as ComboboxItemProps, ["class", "children"]);
return (
<ComboboxPrimitive.Item
class={cn(
"relative z-combobox-item z-select-item flex w-full cursor-default select-none items-center outline-hidden data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
local.class,
)}
data-slot="combobox-item"
{...others}
>
<ComboboxPrimitive.ItemLabel class="z-combobox-item-label z-select-item-text shrink-0 whitespace-nowrap">
{local.children}
</ComboboxPrimitive.ItemLabel>
<ComboboxPrimitive.ItemIndicator
as="span"
class="z-combobox-item-indicator z-select-item-indicator"
>
<Check class="pointer-events-none z-combobox-item-indicator-icon z-select-item-indicator-icon" />
</ComboboxPrimitive.ItemIndicator>
</ComboboxPrimitive.Item>
);
};
// ============================================================================
// Combobox Empty
// ============================================================================
type ComboboxEmptyProps = ComponentProps<"div"> & {
class?: string;
};
const ComboboxEmpty = (props: ComboboxEmptyProps) => {
const [local, others] = splitProps(props, ["class"]);
return (
<div
class={cn("z-combobox-empty py-6 text-center text-sm", local.class)}
data-slot="combobox-empty"
{...others}
/>
);
};
// ============================================================================
// Combobox Separator
// ============================================================================
type ComboboxSeparatorProps<T extends ValidComponent = "hr"> = ComponentProps<T> & {
class?: string;
};
const ComboboxSeparator = <T extends ValidComponent = "hr">(
props: PolymorphicProps<T, ComboboxSeparatorProps<T>>,
) => {
const [local, others] = splitProps(props as ComboboxSeparatorProps, ["class"]);
return (
<hr
class={cn("pointer-events-none z-combobox-separator z-select-separator", local.class)}
data-slot="combobox-separator"
{...others}
/>
);
};
export {
Combobox,
ComboboxContent,
ComboboxControl,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxSection,
ComboboxSectionLabel,
ComboboxSeparator,
ComboboxTrigger,
};

Props

The Combobox component uses Kobalte's Combobox primitive under the hood. Here are the main props:

PropTypeDefaultDescription
optionsT[]-The array of options to display
optionValuekeyof T | ((option: T) => string)-Key or function to get the option's value
optionTextValuekeyof T | ((option: T) => string)-Key or function to get the option's text for filtering
optionDisabledkeyof T | ((option: T) => boolean)-Key or function to determine if option is disabled
optionGroupChildrenkeyof T-Key for grouped options' children array
valueT-The controlled value of the combobox
defaultValueT-The default value of the combobox
onChange(value: T) => void-Handler called when value changes
placeholderstring-Placeholder text when no value is selected
disabledbooleanfalseWhether the combobox is disabled
validationState"valid" | "invalid"-The validation state of the combobox
multiplebooleanfalseWhether multiple options can be selected
defaultFilter"startsWith" | "endsWith" | "contains" | function"contains"The filtering strategy
triggerMode"input" | "focus" | "manual""input"When to open the dropdown

ComboboxInput

PropTypeDefaultDescription
showTriggerbooleantrueShow the dropdown trigger button
showClearbooleanfalseShow the clear button when value is selected
placeholderstring-Placeholder text
disabledbooleanfalseWhether the input is disabled
classstring-Additional CSS classes

ComboboxTrigger

Used for popup-style combobox (button trigger instead of input).

PropTypeDefaultDescription
size"sm" | "default""default"The size variant of the trigger
classstring-Additional CSS classes

ComboboxContent

The ComboboxContent component wraps the dropdown portal and listbox. It inherits positioning from the Combobox root.

ComboboxItem

PropTypeDefaultDescription
itemListState.Option<T>-The item object from Kobalte
disabledbooleanfalseWhether the item is disabled

ComboboxEmpty

Displayed when no options match the filter.

ComboboxSection / ComboboxSectionLabel

Used for grouping options when using optionGroupChildren.

ComboboxSeparator

Visual separator between groups.

Examples

Here are the source code of all the examples from the preview page:

Basic

import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
function ComboboxBasic() {
return (
<Example title="Basic">
<Combobox
options={frameworks}
placeholder="Select a framework..."
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput placeholder="Select a framework..." />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Example>
);
}

Disabled

import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
function ComboboxDisabled() {
return (
<Example title="Disabled">
<Combobox
options={frameworks}
placeholder="Select a framework..."
disabled
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput placeholder="Select a framework..." disabled />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Example>
);
}

Invalid

import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
import { Field, FieldDescription, FieldError, FieldLabel } from "~/components/ui/field";
function ComboboxInvalid() {
return (
<Example title="Invalid">
<div class="flex flex-col gap-4">
<Combobox
options={frameworks}
placeholder="Select a framework..."
validationState="invalid"
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput placeholder="Select a framework..." aria-invalid="true" />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
<Field data-invalid>
<FieldLabel for="combobox-framework-invalid">Framework</FieldLabel>
<Combobox
options={frameworks}
placeholder="Select a framework..."
validationState="invalid"
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput
id="combobox-framework-invalid"
placeholder="Select a framework..."
aria-invalid="true"
/>
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
<FieldDescription>Please select a valid framework.</FieldDescription>
<FieldError errors={[{ message: "This field is required." }]} />
</Field>
</div>
</Example>
);
}

With Clear Button

import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
function ComboboxWithClear() {
return (
<Example title="With Clear Button">
<Combobox
options={frameworks}
placeholder="Select a framework..."
defaultValue={frameworks[0]}
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput placeholder="Select a framework..." showClear />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Example>
);
}

With Groups

import { Show } from "solid-js";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxSection,
ComboboxSectionLabel,
} from "~/components/ui/combobox";
function ComboboxWithGroups() {
return (
<Example title="With Groups">
<Combobox<TimezoneOption, TimezoneGroup>
options={timezones}
optionValue={(opt) => opt}
optionTextValue={(opt) => opt}
optionGroupChildren="options"
placeholder="Select a timezone..."
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
sectionComponent={(props) => (
<ComboboxSection>
<ComboboxSectionLabel>{props.section.rawValue.label}</ComboboxSectionLabel>
</ComboboxSection>
)}
>
<ComboboxInput placeholder="Select a timezone..." />
<ComboboxContent>
<ComboboxEmpty>No timezones found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Example>
);
}

With Groups and Separator

import { Show } from "solid-js";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxSection,
ComboboxSectionLabel,
ComboboxSeparator,
} from "~/components/ui/combobox";
function ComboboxWithGroupsAndSeparator() {
return (
<Example title="With Groups and Separator">
<Combobox<TimezoneOption, TimezoneGroup>
options={timezones}
optionValue={(opt) => opt}
optionTextValue={(opt) => opt}
optionGroupChildren="options"
placeholder="Select a timezone..."
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
sectionComponent={(props) => (
<>
<Show when={props.section.index !== 0}>
<ComboboxSeparator />
</Show>
<ComboboxSection>
<ComboboxSectionLabel>{props.section.rawValue.label}</ComboboxSectionLabel>
</ComboboxSection>
</>
)}
>
<ComboboxInput placeholder="Select a timezone..." />
<ComboboxContent>
<ComboboxEmpty>No timezones found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Example>
);
}

Large List (100 items)

import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
function ComboboxLargeList() {
return (
<Example title="Large List (100 items)">
<Combobox
options={largeList}
optionValue="value"
optionTextValue="label"
placeholder="Search from 100 items..."
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue.label}</ComboboxItem>
)}
>
<ComboboxInput placeholder="Search from 100 items..." />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Example>
);
}

With Icon Addon

import { Globe } from "lucide-solid";
import { Show } from "solid-js";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxSection,
ComboboxSectionLabel,
ComboboxSeparator,
} from "~/components/ui/combobox";
import { InputGroupAddon } from "~/components/ui/input-group";
function ComboboxWithIconAddon() {
return (
<Example title="With Icon Addon">
<Combobox<TimezoneOption, TimezoneGroup>
options={timezones}
optionValue={(opt) => opt}
optionTextValue={(opt) => opt}
optionGroupChildren="options"
placeholder="Select a timezone..."
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
sectionComponent={(props) => (
<>
<Show when={props.section.index !== 0}>
<ComboboxSeparator />
</Show>
<ComboboxSection>
<ComboboxSectionLabel>{props.section.rawValue.label}</ComboboxSectionLabel>
</ComboboxSection>
</>
)}
>
<ComboboxInput placeholder="Select a timezone...">
<InputGroupAddon>
<Globe class="size-4" />
</InputGroupAddon>
</ComboboxInput>
<ComboboxContent class="w-60">
<ComboboxEmpty>No timezones found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Example>
);
}

Form with Combobox

import { toast } from "solid-sonner";
import { Button } from "~/components/ui/button";
import { Card, CardContent, CardFooter } from "~/components/ui/card";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
import { Field, FieldGroup, FieldLabel } from "~/components/ui/field";
function ComboboxWithForm() {
const handleSubmit = (event: SubmitEvent) => {
event.preventDefault();
const formData = new FormData(event.currentTarget as HTMLFormElement);
const framework = formData.get("framework") as string;
toast(`You selected ${framework} as your framework.`);
};
return (
<Example title="Form with Combobox">
<Card class="w-full max-w-sm" size="sm">
<CardContent>
<form id="form-with-combobox" class="w-full" onSubmit={handleSubmit}>
<FieldGroup>
<Field>
<FieldLabel for="framework">Framework</FieldLabel>
<Combobox
options={frameworks}
placeholder="Select a framework..."
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput
id="framework"
name="framework"
placeholder="Select a framework..."
/>
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Field>
</FieldGroup>
</form>
</CardContent>
<CardFooter>
<Button type="submit" form="form-with-combobox">
Submit
</Button>
</CardFooter>
</Card>
</Example>
);
}

Multiple Selection

import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
function ComboboxMultiple() {
return (
<Example title="Multiple Selection">
<Combobox<(typeof frameworks)[number]>
options={frameworks}
placeholder="Select frameworks..."
multiple
defaultValue={[frameworks[0]]}
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput placeholder="Select frameworks..." />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Example>
);
}

Multiple Selection Disabled

import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
function ComboboxMultipleDisabled() {
return (
<Example title="Multiple Selection Disabled">
<Combobox<(typeof frameworks)[number]>
options={frameworks}
placeholder="Select frameworks..."
multiple
disabled
defaultValue={[frameworks[0], frameworks[1]]}
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput placeholder="Select frameworks..." disabled />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Example>
);
}

Multiple Selection Invalid

import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
import { Field, FieldDescription, FieldError, FieldLabel } from "~/components/ui/field";
function ComboboxMultipleInvalid() {
return (
<Example title="Multiple Selection Invalid">
<div class="flex flex-col gap-4">
<Combobox<(typeof frameworks)[number]>
options={frameworks}
placeholder="Select frameworks..."
multiple
validationState="invalid"
defaultValue={[frameworks[0], frameworks[1]]}
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput placeholder="Select frameworks..." aria-invalid="true" />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
<Field data-invalid>
<FieldLabel for="combobox-multiple-invalid">Frameworks</FieldLabel>
<Combobox<(typeof frameworks)[number]>
options={frameworks}
placeholder="Select frameworks..."
multiple
validationState="invalid"
defaultValue={[frameworks[0], frameworks[1], frameworks[2]]}
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput
id="combobox-multiple-invalid"
placeholder="Select frameworks..."
aria-invalid="true"
/>
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
<FieldDescription>Please select at least one framework.</FieldDescription>
<FieldError errors={[{ message: "This field is required." }]} />
</Field>
</div>
</Example>
);
}

With Custom Item Rendering

import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
import { Item, ItemContent, ItemDescription, ItemTitle } from "~/components/ui/item";
function ComboboxWithCustomItems() {
return (
<Example title="With Custom Item Rendering">
<Combobox<(typeof countries)[number]>
options={countries}
optionValue="value"
optionTextValue="label"
placeholder="Search countries..."
itemComponent={(props) => (
<ComboboxItem item={props.item}>
<Item size="xs" class="p-0">
<ItemContent>
<ItemTitle class="whitespace-nowrap">{props.item.rawValue.label}</ItemTitle>
<ItemDescription>
{props.item.rawValue.continent} ({props.item.rawValue.code})
</ItemDescription>
</ItemContent>
</Item>
</ComboboxItem>
)}
>
<ComboboxInput placeholder="Search countries..." />
<ComboboxContent>
<ComboboxEmpty>No countries found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Example>
);
}

With Field

import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
import { Field, FieldDescription, FieldLabel } from "~/components/ui/field";
function ComboboxWithField() {
return (
<Example title="With Field">
<Field>
<FieldLabel for="combobox-framework">Favorite Framework</FieldLabel>
<Combobox
options={frameworks}
placeholder="Select a framework..."
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput id="combobox-framework" placeholder="Select a framework..." />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
<FieldDescription>Choose your favorite JavaScript framework.</FieldDescription>
</Field>
</Example>
);
}

In Dialog

import { createSignal } from "solid-js";
import { toast } from "solid-sonner";
import { Button } from "~/components/ui/button";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "~/components/ui/dialog";
import { Field, FieldLabel } from "~/components/ui/field";
function ComboboxInDialog() {
const [open, setOpen] = createSignal(false);
return (
<Example title="In Dialog">
<Dialog open={open()} onOpenChange={setOpen}>
<DialogTrigger as={Button} variant="outline">
Open Dialog
</DialogTrigger>
<DialogContent class="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Select Framework</DialogTitle>
<DialogDescription>
Choose your preferred framework from the list below.
</DialogDescription>
</DialogHeader>
<Field>
<FieldLabel for="framework-dialog" class="sr-only">
Framework
</FieldLabel>
<Combobox
options={frameworks}
placeholder="Select a framework..."
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput id="framework-dialog" placeholder="Select a framework..." />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
</Field>
<DialogFooter>
<Button type="button" variant="outline" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button
type="button"
onClick={() => {
toast("Framework selected.");
setOpen(false);
}}
>
Confirm
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</Example>
);
}

With Other Inputs

import { ChevronDown } from "lucide-solid";
import { Button } from "~/components/ui/button";
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
} from "~/components/ui/combobox";
import { Input } from "~/components/ui/input";
import { InputGroup, InputGroupAddon, InputGroupInput } from "~/components/ui/input-group";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "~/components/ui/select";
function ComboboxWithOtherInputs() {
return (
<Example title="With Other Inputs">
<Combobox
options={frameworks}
placeholder="Select a framework..."
itemComponent={(props) => (
<ComboboxItem item={props.item}>{props.item.rawValue}</ComboboxItem>
)}
>
<ComboboxInput class="w-52" placeholder="Select a framework..." />
<ComboboxContent>
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
</ComboboxContent>
</Combobox>
<Select<(typeof selectItems)[number]>
options={selectItems}
optionValue="value"
optionTextValue="label"
defaultValue={selectItems[0]}
itemComponent={(props) => (
<SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem>
)}
>
<SelectTrigger class="w-52">
<SelectValue<(typeof selectItems)[number]>>
{(state) => state.selectedOption()?.label}
</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectGroup />
</SelectContent>
</Select>
<Button variant="outline" class="w-52 justify-between font-normal text-muted-foreground">
Select a framework
<ChevronDown class="size-4" />
</Button>
<Input placeholder="Select a framework" class="w-52" />
<InputGroup class="w-52">
<InputGroupInput placeholder="Select a framework" />
<InputGroupAddon align="inline-end">
<ChevronDown class="size-4" />
</InputGroupAddon>
</InputGroup>
</Example>
);
}