Combobox

Preview

import { Check, ChevronsUpDown } from "lucide-react";
import * as React from "react";
import { Button } from "@/registry/components/button/react/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/registry/components/command/react/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/registry/components/popover/react/popover";
import "@/registry/components/popover/popover.css";
import "@/registry/components/command/command.css";
import "@/registry/components/button/button.css";
import cn from "clsx";
const frameworks = [
{
value: "next.js",
label: "Next.js",
},
{
value: "sveltekit",
label: "SvelteKit",
},
{
value: "nuxt.js",
label: "Nuxt.js",
},
{
value: "remix",
label: "Remix",
},
{
value: "astro",
label: "Astro",
},
];
export function ComboboxDemo() {
const [open, setOpen] = React.useState(false);
const [value, setValue] = React.useState("");
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
// biome-ignore lint/a11y/useSemanticElements: Custom combobox implementation
role="combobox"
aria-expanded={open}
>
{value
? frameworks.find((framework) => framework.value === value)?.label
: "Select framework..."}
<ChevronsUpDown />
</Button>
</PopoverTrigger>
<PopoverContent
style={
{
"--popover-width": "var(--popover-trigger-width)",
} as React.CSSProperties
}
>
<Command>
<CommandInput placeholder="Search framework..." />
<CommandList>
<CommandEmpty>No framework found.</CommandEmpty>
<CommandGroup>
{frameworks.map((framework) => (
<CommandItem
key={framework.value}
value={framework.value}
onSelect={(currentValue) => {
setValue(currentValue === value ? "" : currentValue);
setOpen(false);
}}
>
{framework.label}
<Check
className={cn(
"ml-auto",
value === framework.value ? "opacity-100" : "opacity-0"
)}
/>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}

Installation

You can add the combobox component in two ways:

  1. During project initialization:
pnpm dlx make-sugarcube@latest init
npx make-sugarcube@latest init
yarn make-sugarcube@latest init
bunx --bun make-sugarcube@latest init

Then select the combobox component when prompted.

  1. After initialization:
pnpm dlx make-sugarcube@latest components combobox --framework react
npx make-sugarcube@latest components combobox --framework react
yarn make-sugarcube@latest components combobox --framework react
bunx --bun make-sugarcube@latest components combobox --framework react

What’s included

When you add the button component, you get:

  • combobox.tsx - The React component implementation
  • combobox.css - The base styles for the combobox
  • @clsx - The clsx utility for conditional classes
import { Check, ChevronsUpDown } from "lucide-react";
import * as React from "react";
import { Button } from "@/registry/components/button/react/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/registry/components/command/react/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/registry/components/popover/react/popover";
import "@/registry/components/popover/popover.css";
import "@/registry/components/command/command.css";
import "@/registry/components/button/button.css";
import cn from "clsx";
const frameworks = [
{
value: "next.js",
label: "Next.js",
},
{
value: "sveltekit",
label: "SvelteKit",
},
{
value: "nuxt.js",
label: "Nuxt.js",
},
{
value: "remix",
label: "Remix",
},
{
value: "astro",
label: "Astro",
},
];
export function ComboboxDemo() {
const [open, setOpen] = React.useState(false);
const [value, setValue] = React.useState("");
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
// biome-ignore lint/a11y/useSemanticElements: Custom combobox implementation
role="combobox"
aria-expanded={open}
>
{value
? frameworks.find((framework) => framework.value === value)?.label
: "Select framework..."}
<ChevronsUpDown />
</Button>
</PopoverTrigger>
<PopoverContent
style={
{
"--popover-width": "var(--popover-trigger-width)",
} as React.CSSProperties
}
>
<Command>
<CommandInput placeholder="Search framework..." />
<CommandList>
<CommandEmpty>No framework found.</CommandEmpty>
<CommandGroup>
{frameworks.map((framework) => (
<CommandItem
key={framework.value}
value={framework.value}
onSelect={(currentValue) => {
setValue(currentValue === value ? "" : currentValue);
setOpen(false);
}}
>
{framework.label}
<Check
className={cn(
"ml-auto",
value === framework.value ? "opacity-100" : "opacity-0"
)}
/>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}

Examples

:::note The following examples show how to use data attributes for variants. This is just one possible approach. See the principles section for more information on how to approach component variants. :::