Dice UI
Components

Combobox

An input with a popover that helps users filter through a list of options.

Installation

npm install @diceui/combobox

Installation with shadcn/ui

CLI

npx shadcn@latest add "https://diceui.com/r/combobox"

Manual

Install the following dependencies:

npm install @diceui/combobox

Copy and paste the following code into your project.

"use client";
 
import * as ComboboxPrimitive from "@diceui/combobox";
import { Check, ChevronDown, X } from "lucide-react";
import * as React from "react";
 
import { cn } from "@/lib/utils";
 
const Combobox = ComboboxPrimitive.Root;
 
const ComboboxLabel = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Label>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Label>
>(({ className, ...props }, ref) => (
  <ComboboxPrimitive.Label
    ref={ref}
    className={cn("px-0.5 py-1.5 font-semibold text-sm", className)}
    {...props}
  />
));
ComboboxLabel.displayName = ComboboxPrimitive.Label.displayName;
 
const ComboboxAnchor = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Anchor>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Anchor>
>(({ className, ...props }, ref) => (
  <ComboboxPrimitive.Anchor
    ref={ref}
    className={cn(
      "relative flex h-9 w-full items-center justify-between gap-2 rounded-md border border-input bg-transparent px-3 py-2 shadow-xs data-focused:ring-1 data-focused:ring-ring",
      className,
    )}
    {...props}
  />
));
ComboboxAnchor.displayName = ComboboxPrimitive.Anchor.displayName;
 
const ComboboxInput = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Input>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Input>
>(({ className, ...props }, ref) => (
  <ComboboxPrimitive.Input
    ref={ref}
    className={cn(
      "flex h-9 w-full rounded-md bg-transparent text-base placeholder:text-muted-foreground focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
      className,
    )}
    {...props}
  />
));
ComboboxInput.displayName = ComboboxPrimitive.Input.displayName;
 
const ComboboxTrigger = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Trigger>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
  <ComboboxPrimitive.Trigger
    ref={ref}
    className={cn(
      "flex shrink-0 items-center justify-center rounded-r-md border-input bg-transparent text-muted-foreground transition-colors hover:text-foreground/80 focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
      className,
    )}
    {...props}
  >
    {children || <ChevronDown className="h-4 w-4" />}
  </ComboboxPrimitive.Trigger>
));
ComboboxTrigger.displayName = ComboboxPrimitive.Trigger.displayName;
 
const ComboboxCancel = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Cancel>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Cancel>
>(({ className, ...props }, ref) => (
  <ComboboxPrimitive.Cancel
    ref={ref}
    className={cn(
      "-translate-y-1/2 absolute top-1/2 right-1 flex h-6 w-6 items-center justify-center rounded-sm bg-background opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none",
      className,
    )}
    {...props}
  />
));
ComboboxCancel.displayName = ComboboxPrimitive.Cancel.displayName;
 
const ComboboxBadgeList = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.BadgeList>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.BadgeList>
>(({ className, ...props }, ref) => (
  <ComboboxPrimitive.BadgeList
    ref={ref}
    className={cn("flex flex-wrap items-center gap-1.5", className)}
    {...props}
  />
));
ComboboxBadgeList.displayName = ComboboxPrimitive.BadgeList.displayName;
 
const ComboboxBadgeItem = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.BadgeItem>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.BadgeItem>
>(({ className, children, ...props }, ref) => (
  <ComboboxPrimitive.BadgeItem
    ref={ref}
    className={cn(
      "inline-flex items-center justify-between gap-1 rounded-sm bg-secondary px-2 py-0.5",
      className,
    )}
    {...props}
  >
    <span className="truncate text-[13px] text-secondary-foreground">
      {children}
    </span>
    <ComboboxPrimitive.BadgeItemDelete className="shrink-0 rounded p-0.5 opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-highlighted:bg-destructive">
      <X className="h-3 w-3" />
    </ComboboxPrimitive.BadgeItemDelete>
  </ComboboxPrimitive.BadgeItem>
));
ComboboxBadgeItem.displayName = ComboboxPrimitive.BadgeItem.displayName;
 
const ComboboxContent = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Content>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Content>
>(({ className, children, ...props }, ref) => (
  <ComboboxPrimitive.Portal>
    <ComboboxPrimitive.Content
      ref={ref}
      sideOffset={6}
      className={cn(
        "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-fit min-w-[var(--dice-anchor-width)] origin-[var(--dice-transform-origin)] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in",
        className,
      )}
      {...props}
    >
      {children}
    </ComboboxPrimitive.Content>
  </ComboboxPrimitive.Portal>
));
ComboboxContent.displayName = ComboboxPrimitive.Content.displayName;
 
const ComboboxProgress = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Progress>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Progress>
>(({ className, ...props }, ref) => (
  <ComboboxPrimitive.Progress
    ref={ref}
    className={cn("py-6 text-center text-sm", className)}
    {...props}
  >
    Loading...
  </ComboboxPrimitive.Progress>
));
 
const ComboboxEmpty = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Empty>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Empty>
>(({ className, ...props }, ref) => (
  <ComboboxPrimitive.Empty
    ref={ref}
    className={cn("py-6 text-center text-sm", className)}
    {...props}
  />
));
ComboboxEmpty.displayName = ComboboxPrimitive.Empty.displayName;
 
const ComboboxGroup = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Group>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Group>
>(({ className, ...props }, ref) => (
  <ComboboxPrimitive.Group
    ref={ref}
    className={cn("overflow-hidden", className)}
    {...props}
  />
));
ComboboxGroup.displayName = ComboboxPrimitive.Group.displayName;
 
const ComboboxGroupLabel = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.GroupLabel>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.GroupLabel>
>(({ className, ...props }, ref) => (
  <ComboboxPrimitive.GroupLabel
    ref={ref}
    className={cn(
      "px-2 py-1.5 font-semibold text-muted-foreground text-xs",
      className,
    )}
    {...props}
  />
));
ComboboxGroupLabel.displayName = ComboboxPrimitive.GroupLabel.displayName;
 
const ComboboxItem = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Item>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Item> & {
    outset?: boolean;
  }
>(({ className, children, outset, ...props }, ref) => (
  <ComboboxPrimitive.Item
    ref={ref}
    className={cn(
      "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 text-sm outline-hidden data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-50",
      outset ? "pr-8 pl-2" : "pr-2 pl-8",
      className,
    )}
    {...props}
  >
    <ComboboxPrimitive.ItemIndicator
      className={cn(
        "absolute flex h-3.5 w-3.5 items-center justify-center",
        outset ? "right-2" : "left-2",
      )}
    >
      <Check className="h-4 w-4" />
    </ComboboxPrimitive.ItemIndicator>
    <ComboboxPrimitive.ItemText>{children}</ComboboxPrimitive.ItemText>
  </ComboboxPrimitive.Item>
));
ComboboxItem.displayName = ComboboxPrimitive.Item.displayName;
 
const ComboboxSeparator = React.forwardRef<
  React.ElementRef<typeof ComboboxPrimitive.Separator>,
  React.ComponentPropsWithoutRef<typeof ComboboxPrimitive.Separator>
>(({ className, ...props }, ref) => (
  <ComboboxPrimitive.Separator
    ref={ref}
    className={cn("-mx-1 my-1 h-px bg-muted", className)}
    {...props}
  />
));
ComboboxSeparator.displayName = ComboboxPrimitive.Separator.displayName;
 
export {
  Combobox,
  ComboboxAnchor,
  ComboboxInput,
  ComboboxTrigger,
  ComboboxCancel,
  ComboboxBadgeList,
  ComboboxBadgeItem,
  ComboboxContent,
  ComboboxEmpty,
  ComboboxGroup,
  ComboboxGroupLabel,
  ComboboxItem,
  ComboboxLabel,
  ComboboxProgress,
  ComboboxSeparator,
};

Layout

Import the parts, and compose them together.

import * as Combobox from "@diceui/combobox";
 
<Combobox.Root>
  <Combobox.Label />
  <Combobox.Anchor>
    <Combobox.BadgeList>
      <Combobox.BadgeItem>
        <Combobox.BadgeItemDelete />
      </Combobox.BadgeItem>
    </Combobox.BadgeList>
    <Combobox.Input />
    <Combobox.Trigger />
    <Combobox.Cancel />
  </Combobox.Anchor>
  <Combobox.Portal>
    <Combobox.Content>
      <Combobox.Arrow />
      <Combobox.Progress />
      <Combobox.Empty />
      <Combobox.Group>
        <Combobox.GroupLabel />
        <Combobox.Item>
          <Combobox.ItemText />
          <Combobox.ItemIndicator />
        </Combobox.Item>
      </Combobox.Group>
      <Combobox.Separator />
    </Combobox.Content>
  </Combobox.Portal>
</Combobox.Root>

Examples

With Groups

With Multiple Selection

With Custom Filter

With Debounce

With Virtualization

With Tags Input

API Reference

Root

The container for all combobox parts.

PropTypeDefault
defaultValue
Value<Multiple>
-
value
Value<Multiple>
-
onValueChange
(value: Value<Multiple>) => void
-
asChild
boolean
-
open
boolean
-
defaultOpen
boolean
false
onOpenChange
(open: boolean) => void
-
inputValue
string
-
onInputValueChange
(value: string) => void
-
onFilter
(options: string[], inputValue: string) => string[]
-
autoHighlight
boolean
false
disabled
boolean
-
exactMatch
boolean
false
manualFiltering
boolean
true
loop
boolean
false
modal
boolean
false
multiple
Multiple
false
openOnFocus
boolean
false
preserveInputOnBlur
boolean
false
readOnly
boolean
false
required
boolean
false
name
string
-
Data AttributeValue
[data-state]"open" | "closed"
[data-disabled]Present when disabled.

Label

An accessible label that describes the combobox. Associates with the input element for screen readers.

PropTypeDefault
asChild
boolean
-

Anchor

A wrapper element that positions the combobox popover relative to the input and trigger. Provides the reference point for popover positioning.

PropTypeDefault
asChild
boolean
-
preventInputFocus
boolean
false
Data AttributeValue
[data-state]"open" | "closed"
[data-anchor]Present when the anchor is present.
[data-disabled]Present when disabled.
[data-focused]Present when the anchor is focused.

Trigger

A button that toggles the combobox popover. Handles focus management and keyboard interactions for opening/closing the popover.

PropTypeDefault
asChild
boolean
-
Data AttributeValue
[data-state]"open" | "closed"
[data-disabled]Present when disabled

Input

The text input field that users can type into to filter options.

PropTypeDefault
asChild
boolean
-

BadgeList

A container for displaying selected items as badges in a multi-select combobox.

PropTypeDefault
asChild
boolean
-
forceMount
boolean
false
orientation
"horizontal" | "vertical"
"horizontal"
Data AttributeValue
[data-orientation]"horizontal" | "vertical"

BadgeItem

An individual badge representing a selected item in a multi-select combobox.

PropTypeDefault
asChild
boolean
-
value
string
-
disabled
boolean
false
Data AttributeValue
[data-disabled]Present when the badge is disabled.
[data-highlighted]Present when the badge is highlighted.
[data-orientation]"horizontal" | "vertical"

BadgeItemDelete

A button to remove a selected item from the multi-select combobox.

PropTypeDefault
asChild
boolean
-
Data AttributeValue
[data-disabled]Present when the parent badge is disabled.
[data-highlighted]Present when the parent badge is highlighted.

Cancel

A button that clears the input value and resets the filter.

PropTypeDefault
asChild
boolean
-
forceMount
boolean
false

Portal

A portal for rendering the combobox content outside of its DOM hierarchy.

PropTypeDefault
container
HTMLElement | DocumentFragment
document.body

Content

The popover container for combobox items. Positions the combobox popover relative to the anchor.

PropTypeDefault
side
Side
"bottom"
sideOffset
number
4
align
Align
"start"
alignOffset
number
0
collisionBoundary
Boundary
-
collisionPadding
number | Partial<Record<Side, number>>
0
arrowPadding
number
0
sticky
"partial" | "always"
"partial"
strategy
Strategy
"absolute"
avoidCollisions
boolean
true
fitViewport
boolean
false
forceMount
boolean
false
hideWhenDetached
boolean
false
trackAnchor
boolean
true
asChild
boolean
-
onEscapeKeyDown
(event: KeyboardEvent) => void
-
onPointerDownOutside
(event: PointerDownOutsideEvent) => void
-
Data AttributeValue
[data-state]"open" | "closed"
[data-side]"top" | "right" | "bottom" | "left"
[data-align]"start" | "center" | "end"
CSS VariableDescriptionDefault
--dice-transform-originTransform origin for anchor positioning.
--dice-anchor-widthWidth of the anchor element.
--dice-anchor-heightHeight of the anchor element.
--dice-available-widthAvailable width in the viewport for the popover element.
--dice-available-heightAvailable height in the viewport for the popover element.

Arrow

A visual arrow element that points to the anchor.

PropTypeDefault
asChild
boolean
-

Progress

A loading indicator for asynchronous filtering operations.

PropTypeDefault
label
string
-
asChild
boolean
-
value
number
null
max
number
100

Empty

A placeholder component displayed when no options match the current filter.

PropTypeDefault
asChild
boolean
-
keepVisible
boolean
false

Group

A container for logically grouping related options.

PropTypeDefault
asChild
boolean
-
forceMount
boolean
false

GroupLabel

A label that describes a group of options.

PropTypeDefault
asChild
boolean
-

Item

An interactive item in the combobox list.

PropTypeDefault
label
string
-
onSelect
(value: string) => void
-
asChild
boolean
-
value
string
-
disabled
boolean
-
Data AttributeValue
[data-highlighted]Present when the item is highlighted.
[data-disabled]Present when the item is disabled.
[data-state]"checked" | "unchecked"

ItemText

The textual content of an item.

PropTypeDefault
asChild
boolean
-

ItemIndicator

A visual indicator for selected options.

PropTypeDefault
asChild
boolean
-
forceMount
boolean
false

Separator

A visual divider for separating options or groups.

PropTypeDefault
asChild
boolean
-
keepVisible
boolean
false

Accessibility

Keyboard Interactions

KeyDescription
EnterWhen open, selects the highlighted option. When a badge is highlighted in multiple mode, removes the badge.
ArrowUpWhen open, highlights the previous option.
ArrowDownWhen open, highlights the next option.
ArrowLeftIn multiple mode: When cursor is at start of input, closes the menu and highlights the last badge. When a badge is highlighted, moves highlight to previous badge.
ArrowRightIn multiple mode: When a badge is highlighted, moves highlight to next badge. If on last badge, removes highlight and focuses input.
BackspaceDeleteIn multiple mode: When input is empty, removes the last badge. When a badge is highlighted, removes the highlighted badge.
HomeWhen open, highlights the first option.
EndWhen open, highlights the last option.
PageUpWhen open and modal is enabled, highlights the previous option.
PageDownWhen open and modal is enabled, highlights the next option.
EscapeCloses the combobox popover, returns focus to the input, and resets or restores the input value.