Combobox
Autocomplete input with a filterable list of suggestions, single or multi-select.
npx shadcn@latest add @velaui/comboboxpnpm dlx velaui add @velaui/comboboxyarn dlx shadcn@latest add @velaui/comboboxbunx --bun shadcn@latest add @velaui/comboboxveni add comboboxInstalls the copy of vela-ui that veni-builder serves to Venizia apps; veni-builder serves the Radix UI copy only, so this tab exists for that base alone.
npx shadcn@latest add @velaui/comboboxpnpm dlx velaui add @velaui/comboboxyarn dlx shadcn@latest add @velaui/comboboxbunx --bun shadcn@latest add @velaui/comboboxExamples
- Default
- Fill medium
- Underline large
- Disabled
- Invalid
- Grouped
- Multiple
Usage
Props
ComboboxInput
| Prop | Type | Default |
|---|---|---|
disabled | boolean | false |
showClear | boolean | false |
showTrigger | boolean | true |
size | "sm" | "md" | "lg" | "sm" |
variant | "fill" | "underline" | "outlined" | "outlined" |
Takes these and every prop of ComboboxInputProps.
ComboboxContent
| Prop | Type | Default |
|---|---|---|
align | import("/app/node_modules/.bun/@base-ui+react@1.6.0+df7f6a806acd27ca/node_modules/@base-ui/react/utils/useAnchorPositioning").Align | "start" |
alignOffset | number | import("/app/node_modules/.bun/@base-ui+react@1.6.0+df7f6a806acd27ca/node_modules/@base-ui/react/utils/useAnchorPositioning").OffsetFunction | 0 |
side | import("/app/node_modules/.bun/@base-ui+react@1.6.0+df7f6a806acd27ca/node_modules/@base-ui/react/utils/useAnchorPositioning").Side | "bottom" |
sideOffset | number | import("/app/node_modules/.bun/@base-ui+react@1.6.0+df7f6a806acd27ca/node_modules/@base-ui/react/utils/useAnchorPositioning").OffsetFunction | 4 |
Takes these and every prop of ComboboxContentProps.
ComboboxList
Takes every prop of ComboboxListProps.
ComboboxItem
Takes every prop of ComboboxItemProps.
ComboboxGroup
Takes every prop of ComboboxGroupProps.
ComboboxLabel
Takes every prop of ComboboxLabelProps.
ComboboxCollection
Takes every prop of ComboboxCollectionProps.
ComboboxEmpty
Takes every prop of ComboboxEmptyProps.
ComboboxSeparator
Takes every prop of ComboboxSeparatorProps.
ComboboxChips
Takes every prop of ComboboxChipsProps.
ComboboxChip
| Prop | Type | Default |
|---|---|---|
showRemove | boolean | true |
Takes these and every prop of ComboboxChipProps.
ComboboxChipsInput
Takes every prop of ComboboxChipsInputProps.
ComboboxTrigger
Takes every prop of ComboboxTriggerProps.
ComboboxValue
Takes every prop of ComboboxValueProps.
ComboboxInput
| Prop | Type | Default |
|---|---|---|
disabled | boolean | false |
showClear | boolean | false |
showTrigger | boolean | true |
size | "sm" | "md" | "lg" | "sm" |
variant | "underline" | "fill" | "outlined" | "outlined" |
Takes these and every prop of ComboboxInputProps.
ComboboxContent
| Prop | Type | Default |
|---|---|---|
align | import("/app/node_modules/.bun/@base-ui+react@1.6.0+df7f6a806acd27ca/node_modules/@base-ui/react/utils/useAnchorPositioning").Align | "start" |
alignOffset | number | import("/app/node_modules/.bun/@base-ui+react@1.6.0+df7f6a806acd27ca/node_modules/@base-ui/react/utils/useAnchorPositioning").OffsetFunction | 0 |
side | import("/app/node_modules/.bun/@base-ui+react@1.6.0+df7f6a806acd27ca/node_modules/@base-ui/react/utils/useAnchorPositioning").Side | "bottom" |
sideOffset | number | import("/app/node_modules/.bun/@base-ui+react@1.6.0+df7f6a806acd27ca/node_modules/@base-ui/react/utils/useAnchorPositioning").OffsetFunction | 4 |
Takes these and every prop of ComboboxContentProps.
ComboboxList
Takes every prop of ComboboxListProps.
ComboboxItem
Takes every prop of ComboboxItemProps.
ComboboxGroup
Takes every prop of ComboboxGroupProps.
ComboboxLabel
Takes every prop of ComboboxLabelProps.
ComboboxCollection
Takes every prop of ComboboxCollectionProps.
ComboboxEmpty
Takes every prop of ComboboxEmptyProps.
ComboboxSeparator
Takes every prop of ComboboxSeparatorProps.
ComboboxChips
Takes every prop of ComboboxChipsProps.
ComboboxChip
| Prop | Type | Default |
|---|---|---|
showRemove | boolean | true |
Takes these and every prop of ComboboxChipProps.
ComboboxChipsInput
Takes every prop of ComboboxChipsInputProps.
ComboboxTrigger
Takes every prop of ComboboxTriggerProps.
ComboboxValue
Takes every prop of ComboboxValueProps.
Dependencies
- npm
@base-ui/react@1.6.0class-variance-authority@0.7.1- Installs with it
- ButtonInput Group3 icons
Source
components/ui/combobox.tsx
/* eslint-disable react-refresh/only-export-components */
"use client";
import * as React from "react";
import { Combobox as ComboboxPrimitive } from "@base-ui/react";
import { type VariantProps } from "class-variance-authority";
import { Check01 } from "@/components/icons/check-01";
import { ChevronDown } from "@/components/icons/chevron-down";
import { Close02 } from "@/components/icons/close-02";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
inputGroupVariants,
} from "@/components/ui/input-group";
export type ComboboxProps = React.ComponentProps<typeof ComboboxPrimitive.Root>;
const Combobox = ComboboxPrimitive.Root;
export type ComboboxValueProps = ComboboxPrimitive.Value.Props;
function ComboboxValue({ ...props }: ComboboxValueProps) {
return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />;
}
export type ComboboxTriggerProps = ComboboxPrimitive.Trigger.Props;
function ComboboxTrigger({
className,
children,
...props
}: ComboboxTriggerProps) {
return (
<ComboboxPrimitive.Trigger
data-slot="combobox-trigger"
className={cn(
// Open flips the chevron — the only thing the trigger itself restyles.
"text-icon-muted data-popup-open:[&>svg]:rotate-180 [&_svg:not([class*='size-'])]:size-4",
className,
)}
{...props}
>
{children}
<ChevronDown className="pointer-events-none size-4 text-icon-muted transition-transform" />
</ComboboxPrimitive.Trigger>
);
}
function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
return (
<ComboboxPrimitive.Clear
data-slot="combobox-clear"
render={<InputGroupButton variant="ghost" size="icon-xs" />}
className={cn("text-icon-muted", className)}
{...props}
>
<Close02 className="pointer-events-none" />
</ComboboxPrimitive.Clear>
);
}
export type ComboboxInputProps = Omit<ComboboxPrimitive.Input.Props, "size"> & {
showTrigger?: boolean;
showClear?: boolean;
} & VariantProps<typeof inputGroupVariants>;
function ComboboxInput({
className,
children,
disabled = false,
showTrigger = true,
showClear = false,
variant = "outlined",
size = "sm",
...props
}: ComboboxInputProps) {
return (
<InputGroup
variant={variant}
size={size}
className={cn("w-auto", className)}
>
<ComboboxPrimitive.Input
render={<InputGroupInput disabled={disabled} />}
{...props}
/>
<InputGroupAddon align="inline-end">
{showTrigger && (
<InputGroupButton
size="icon-xs"
variant="ghost"
asChild
data-slot="input-group-button"
className="group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent"
disabled={disabled}
>
<ComboboxTrigger />
</InputGroupButton>
)}
{showClear && <ComboboxClear disabled={disabled} />}
</InputGroupAddon>
{children}
</InputGroup>
);
}
export type ComboboxContentProps = ComboboxPrimitive.Popup.Props &
Pick<
ComboboxPrimitive.Positioner.Props,
"side" | "align" | "sideOffset" | "alignOffset" | "anchor"
>;
function ComboboxContent({
className,
side = "bottom",
sideOffset = 4,
align = "start",
alignOffset = 0,
anchor,
...props
}: ComboboxContentProps) {
return (
<ComboboxPrimitive.Portal>
<ComboboxPrimitive.Positioner
side={side}
sideOffset={sideOffset}
align={align}
alignOffset={alignOffset}
anchor={anchor}
className="isolate z-50"
>
<ComboboxPrimitive.Popup
data-slot="combobox-content"
data-chips={!!anchor}
className={cn(
"group/combobox-content relative max-h-(--available-height) w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-md border border-border-default bg-bg-main text-text-strong shadow-md duration-100 data-[chips=true]:min-w-(--anchor-width) data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-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 *:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className,
)}
{...props}
/>
</ComboboxPrimitive.Positioner>
</ComboboxPrimitive.Portal>
);
}
export type ComboboxListProps = ComboboxPrimitive.List.Props;
function ComboboxList({ className, ...props }: ComboboxListProps) {
return (
<ComboboxPrimitive.List
data-slot="combobox-list"
className={cn(
"no-scrollbar flex max-h-[min(calc(--spacing(72)---spacing(9)),calc(var(--available-height)---spacing(9)))] scroll-py-1 flex-col gap-1 overflow-y-auto overscroll-contain p-1 data-empty:p-0",
className,
)}
{...props}
/>
);
}
export type ComboboxItemProps = ComboboxPrimitive.Item.Props;
function ComboboxItem({
className,
children,
...props
}: ComboboxItemProps) {
return (
<ComboboxPrimitive.Item
data-slot="combobox-item"
className={cn(
"relative flex w-full cursor-default items-center gap-2 rounded-md py-1.5 pr-10 pl-2 text-sm leading-[1.4] text-text-strong outline-hidden select-none data-highlighted:bg-bg-surface-1 data-selected:bg-bg-surface-1 data-disabled:pointer-events-none data-disabled:text-text-disabled [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-5",
className,
)}
{...props}
>
{children}
<ComboboxPrimitive.ItemIndicator
render={
<span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
}
>
<Check01 className="pointer-events-none size-4 text-icon-strong" />
</ComboboxPrimitive.ItemIndicator>
</ComboboxPrimitive.Item>
);
}
export type ComboboxGroupProps = ComboboxPrimitive.Group.Props;
function ComboboxGroup({ className, ...props }: ComboboxGroupProps) {
return (
<ComboboxPrimitive.Group
data-slot="combobox-group"
className={cn("flex scroll-my-1 flex-col gap-1", className)}
{...props}
/>
);
}
export type ComboboxLabelProps = ComboboxPrimitive.GroupLabel.Props;
function ComboboxLabel({
className,
...props
}: ComboboxLabelProps) {
return (
<ComboboxPrimitive.GroupLabel
data-slot="combobox-label"
className={cn("px-2 py-1 text-xs text-text-muted", className)}
{...props}
/>
);
}
export type ComboboxCollectionProps = ComboboxPrimitive.Collection.Props;
function ComboboxCollection({ ...props }: ComboboxCollectionProps) {
return (
<ComboboxPrimitive.Collection data-slot="combobox-collection" {...props} />
);
}
export type ComboboxEmptyProps = ComboboxPrimitive.Empty.Props;
function ComboboxEmpty({ className, ...props }: ComboboxEmptyProps) {
return (
<ComboboxPrimitive.Empty
data-slot="combobox-empty"
className={cn(
"hidden w-full justify-center py-2 text-center text-sm text-text-muted group-data-empty/combobox-content:flex",
className,
)}
{...props}
/>
);
}
export type ComboboxSeparatorProps = ComboboxPrimitive.Separator.Props;
function ComboboxSeparator({
className,
...props
}: ComboboxSeparatorProps) {
return (
<ComboboxPrimitive.Separator
data-slot="combobox-separator"
className={cn(
"pointer-events-none -mx-1 my-1 h-px bg-border-default",
className,
)}
{...props}
/>
);
}
export type ComboboxChipsProps = React.ComponentPropsWithRef<typeof ComboboxPrimitive.Chips> &
ComboboxPrimitive.Chips.Props;
function ComboboxChips({
className,
...props
}: ComboboxChipsProps) {
return (
<ComboboxPrimitive.Chips
data-slot="combobox-chips"
className={cn(
"flex min-h-8 flex-wrap items-center gap-1 rounded-md border border-border-default bg-bg-main bg-clip-padding px-2.5 py-1 text-sm leading-[1.4] text-text-strong transition-colors focus-within:border-ring-neutral-outline focus-within:ring-3 focus-within:ring-ring-neutral-shadow has-aria-invalid:border-negative-middle has-aria-invalid:ring-3 has-aria-invalid:ring-negative-middle/25 has-data-[slot=combobox-chip]:px-1",
className,
)}
{...props}
/>
);
}
export type ComboboxChipProps = ComboboxPrimitive.Chip.Props & {
showRemove?: boolean;
};
function ComboboxChip({
className,
children,
showRemove = true,
...props
}: ComboboxChipProps) {
return (
<ComboboxPrimitive.Chip
data-slot="combobox-chip"
className={cn(
"flex h-[calc(--spacing(5.25))] w-fit items-center justify-center gap-1 rounded-sm bg-bg-surface-1 px-1.5 text-xs font-medium whitespace-nowrap text-text-strong has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:text-text-disabled has-data-[slot=combobox-chip-remove]:pr-0",
className,
)}
{...props}
>
{children}
{showRemove && (
<ComboboxPrimitive.ChipRemove
render={<Button variant="ghost" size="icon-xs" />}
className="-ml-1 text-icon-muted opacity-50 hover:opacity-100 hover:bg-transparent"
data-slot="combobox-chip-remove"
>
<Close02 className="pointer-events-none" />
</ComboboxPrimitive.ChipRemove>
)}
</ComboboxPrimitive.Chip>
);
}
export type ComboboxChipsInputProps = ComboboxPrimitive.Input.Props;
function ComboboxChipsInput({
className,
...props
}: ComboboxChipsInputProps) {
return (
<ComboboxPrimitive.Input
data-slot="combobox-chip-input"
className={cn(
"min-w-16 flex-1 text-sm leading-[1.4] text-text-strong outline-none placeholder:text-text-note",
className,
)}
{...props}
/>
);
}
function useComboboxAnchor() {
return React.useRef<HTMLDivElement | null>(null);
}
export {
Combobox,
ComboboxInput,
ComboboxContent,
ComboboxList,
ComboboxItem,
ComboboxGroup,
ComboboxLabel,
ComboboxCollection,
ComboboxEmpty,
ComboboxSeparator,
ComboboxChips,
ComboboxChip,
ComboboxChipsInput,
ComboboxTrigger,
ComboboxValue,
useComboboxAnchor,
};components/ui/combobox.tsx
/* eslint-disable react-refresh/only-export-components */
"use client";
import * as React from "react";
import { Combobox as ComboboxPrimitive } from "@base-ui/react";
import { type VariantProps } from "class-variance-authority";
import { Check01 } from "@/components/icons/check-01";
import { ChevronDown } from "@/components/icons/chevron-down";
import { Close02 } from "@/components/icons/close-02";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
inputGroupVariants,
} from "@/components/ui/input-group";
export type ComboboxProps = React.ComponentProps<typeof ComboboxPrimitive.Root>;
const Combobox = ComboboxPrimitive.Root;
export type ComboboxValueProps = ComboboxPrimitive.Value.Props;
function ComboboxValue({ ...props }: ComboboxValueProps) {
return <ComboboxPrimitive.Value data-slot="combobox-value" {...props} />;
}
export type ComboboxTriggerProps = ComboboxPrimitive.Trigger.Props;
function ComboboxTrigger({
className,
children,
...props
}: ComboboxTriggerProps) {
return (
<ComboboxPrimitive.Trigger
data-slot="combobox-trigger"
className={cn(
// Open flips the chevron — the only thing the trigger itself restyles.
"text-icon-muted data-popup-open:[&>svg]:rotate-180 [&_svg:not([class*='size-'])]:size-4",
className,
)}
{...props}
>
{children}
<ChevronDown className="pointer-events-none size-4 text-icon-muted transition-transform" />
</ComboboxPrimitive.Trigger>
);
}
function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
return (
<ComboboxPrimitive.Clear
data-slot="combobox-clear"
render={<InputGroupButton variant="ghost" size="icon-xs" />}
className={cn("text-icon-muted", className)}
{...props}
>
<Close02 className="pointer-events-none" />
</ComboboxPrimitive.Clear>
);
}
export type ComboboxInputProps = Omit<ComboboxPrimitive.Input.Props, "size"> & {
showTrigger?: boolean;
showClear?: boolean;
} & VariantProps<typeof inputGroupVariants>;
function ComboboxInput({
className,
children,
disabled = false,
showTrigger = true,
showClear = false,
variant = "outlined",
size = "sm",
...props
}: ComboboxInputProps) {
return (
<InputGroup
variant={variant}
size={size}
className={cn("w-auto", className)}
>
<ComboboxPrimitive.Input
render={<InputGroupInput disabled={disabled} />}
{...props}
/>
<InputGroupAddon align="inline-end">
{showTrigger && (
<InputGroupButton
size="icon-xs"
variant="ghost"
render={<ComboboxTrigger />}
data-slot="input-group-button"
className="group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent"
disabled={disabled}
/>
)}
{showClear && <ComboboxClear disabled={disabled} />}
</InputGroupAddon>
{children}
</InputGroup>
);
}
export type ComboboxContentProps = ComboboxPrimitive.Popup.Props &
Pick<
ComboboxPrimitive.Positioner.Props,
"side" | "align" | "sideOffset" | "alignOffset" | "anchor"
>;
function ComboboxContent({
className,
side = "bottom",
sideOffset = 4,
align = "start",
alignOffset = 0,
anchor,
...props
}: ComboboxContentProps) {
return (
<ComboboxPrimitive.Portal>
<ComboboxPrimitive.Positioner
side={side}
sideOffset={sideOffset}
align={align}
alignOffset={alignOffset}
anchor={anchor}
className="isolate z-50"
>
<ComboboxPrimitive.Popup
data-slot="combobox-content"
data-chips={!!anchor}
className={cn(
"group/combobox-content relative max-h-(--available-height) w-(--anchor-width) max-w-(--available-width) min-w-[calc(var(--anchor-width)+--spacing(7))] origin-(--transform-origin) overflow-hidden rounded-md border border-border-default bg-bg-main text-text-strong shadow-md duration-100 data-[chips=true]:min-w-(--anchor-width) data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-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 *:data-[slot=input-group]:m-1 *:data-[slot=input-group]:mb-0 *:data-[slot=input-group]:h-8 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
className,
)}
{...props}
/>
</ComboboxPrimitive.Positioner>
</ComboboxPrimitive.Portal>
);
}
export type ComboboxListProps = ComboboxPrimitive.List.Props;
function ComboboxList({ className, ...props }: ComboboxListProps) {
return (
<ComboboxPrimitive.List
data-slot="combobox-list"
className={cn(
"no-scrollbar flex max-h-[min(calc(--spacing(72)---spacing(9)),calc(var(--available-height)---spacing(9)))] scroll-py-1 flex-col gap-1 overflow-y-auto overscroll-contain p-1 data-empty:p-0",
className,
)}
{...props}
/>
);
}
export type ComboboxItemProps = ComboboxPrimitive.Item.Props;
function ComboboxItem({
className,
children,
...props
}: ComboboxItemProps) {
return (
<ComboboxPrimitive.Item
data-slot="combobox-item"
className={cn(
"relative flex w-full cursor-default items-center gap-2 rounded-md py-1.5 pr-10 pl-2 text-sm leading-[1.4] text-text-strong outline-hidden select-none data-highlighted:bg-bg-surface-1 data-selected:bg-bg-surface-1 data-disabled:pointer-events-none data-disabled:text-text-disabled [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-5",
className,
)}
{...props}
>
{children}
<ComboboxPrimitive.ItemIndicator
render={
<span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
}
>
<Check01 className="pointer-events-none size-4 text-icon-strong" />
</ComboboxPrimitive.ItemIndicator>
</ComboboxPrimitive.Item>
);
}
export type ComboboxGroupProps = ComboboxPrimitive.Group.Props;
function ComboboxGroup({ className, ...props }: ComboboxGroupProps) {
return (
<ComboboxPrimitive.Group
data-slot="combobox-group"
className={cn("flex scroll-my-1 flex-col gap-1", className)}
{...props}
/>
);
}
export type ComboboxLabelProps = ComboboxPrimitive.GroupLabel.Props;
function ComboboxLabel({
className,
...props
}: ComboboxLabelProps) {
return (
<ComboboxPrimitive.GroupLabel
data-slot="combobox-label"
className={cn("px-2 py-1 text-xs text-text-muted", className)}
{...props}
/>
);
}
export type ComboboxCollectionProps = ComboboxPrimitive.Collection.Props;
function ComboboxCollection({ ...props }: ComboboxCollectionProps) {
return (
<ComboboxPrimitive.Collection data-slot="combobox-collection" {...props} />
);
}
export type ComboboxEmptyProps = ComboboxPrimitive.Empty.Props;
function ComboboxEmpty({ className, ...props }: ComboboxEmptyProps) {
return (
<ComboboxPrimitive.Empty
data-slot="combobox-empty"
className={cn(
"hidden w-full justify-center py-2 text-center text-sm text-text-muted group-data-empty/combobox-content:flex",
className,
)}
{...props}
/>
);
}
export type ComboboxSeparatorProps = ComboboxPrimitive.Separator.Props;
function ComboboxSeparator({
className,
...props
}: ComboboxSeparatorProps) {
return (
<ComboboxPrimitive.Separator
data-slot="combobox-separator"
className={cn(
"pointer-events-none -mx-1 my-1 h-px bg-border-default",
className,
)}
{...props}
/>
);
}
export type ComboboxChipsProps = React.ComponentPropsWithRef<typeof ComboboxPrimitive.Chips> &
ComboboxPrimitive.Chips.Props;
function ComboboxChips({
className,
...props
}: ComboboxChipsProps) {
return (
<ComboboxPrimitive.Chips
data-slot="combobox-chips"
className={cn(
"flex min-h-8 flex-wrap items-center gap-1 rounded-md border border-border-default bg-bg-main bg-clip-padding px-2.5 py-1 text-sm leading-[1.4] text-text-strong transition-colors focus-within:border-ring-neutral-outline focus-within:ring-3 focus-within:ring-ring-neutral-shadow has-aria-invalid:border-negative-middle has-aria-invalid:ring-3 has-aria-invalid:ring-negative-middle/25 has-data-[slot=combobox-chip]:px-1",
className,
)}
{...props}
/>
);
}
export type ComboboxChipProps = ComboboxPrimitive.Chip.Props & {
showRemove?: boolean;
};
function ComboboxChip({
className,
children,
showRemove = true,
...props
}: ComboboxChipProps) {
return (
<ComboboxPrimitive.Chip
data-slot="combobox-chip"
className={cn(
"flex h-[calc(--spacing(5.25))] w-fit items-center justify-center gap-1 rounded-sm bg-bg-surface-1 px-1.5 text-xs font-medium whitespace-nowrap text-text-strong has-disabled:pointer-events-none has-disabled:cursor-not-allowed has-disabled:text-text-disabled has-data-[slot=combobox-chip-remove]:pr-0",
className,
)}
{...props}
>
{children}
{showRemove && (
<ComboboxPrimitive.ChipRemove
render={<Button variant="ghost" size="icon-xs" />}
className="-ml-1 text-icon-muted opacity-50 hover:opacity-100 hover:bg-transparent"
data-slot="combobox-chip-remove"
>
<Close02 className="pointer-events-none" />
</ComboboxPrimitive.ChipRemove>
)}
</ComboboxPrimitive.Chip>
);
}
export type ComboboxChipsInputProps = ComboboxPrimitive.Input.Props;
function ComboboxChipsInput({
className,
...props
}: ComboboxChipsInputProps) {
return (
<ComboboxPrimitive.Input
data-slot="combobox-chip-input"
className={cn(
"min-w-16 flex-1 text-sm leading-[1.4] text-text-strong outline-none placeholder:text-text-note",
className,
)}
{...props}
/>
);
}
function useComboboxAnchor() {
return React.useRef<HTMLDivElement | null>(null);
}
export {
Combobox,
ComboboxInput,
ComboboxContent,
ComboboxList,
ComboboxItem,
ComboboxGroup,
ComboboxLabel,
ComboboxCollection,
ComboboxEmpty,
ComboboxSeparator,
ComboboxChips,
ComboboxChip,
ComboboxChipsInput,
ComboboxTrigger,
ComboboxValue,
useComboboxAnchor,
};