PRIZM 4.0DSTA
All components

Combobox

Searchable select with typeahead.

stableBase UI Combobox

Preview

Code

tsx
import {
  Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput,
  ComboboxItem, ComboboxList,
} from "@/components/ui/combobox";

const items = [
  "C3 product",
  "Enterprise product",
  "Mobile app",
  "Internal tool",
  "Marketing site",
];

export function Example() {
  return (
    <Combobox items={items}>
      <ComboboxInput placeholder="Search products…" className="w-56" />
      <ComboboxContent>
        <ComboboxList>
          {(item) => (
            <ComboboxItem key={item} value={item}>
              {item}
            </ComboboxItem>
          )}
        </ComboboxList>
        <ComboboxEmpty>No results.</ComboboxEmpty>
      </ComboboxContent>
    </Combobox>
  );
}

Props

PropTypeDefaultDescription
valuestringControlled selected value.
defaultValuestringUncontrolled initial value.
onValueChange(value: string) => voidCalled when the selection changes.
itemsreadonly any[]Items to filter against the input query. Pair with a render-function child on ComboboxList to render each filtered item.

Sub-components

ComboboxInputThe search input that is both the trigger and the query field. Focus or type to open the popup; the input's value drives filtering against the `items` prop.
PropTypeDefaultDescription
classNamestringAdditional Tailwind classes, merged with the component's defaults via cn().
ComboboxContentThe popup with the filterable list. Portals to document body.
PropTypeDefaultDescription
classNamestringAdditional Tailwind classes, merged with the component's defaults via cn().
ComboboxListThe list container. Accepts either static children or a render function `(item) => ReactNode` when `items` is set on the root.
PropTypeDefaultDescription
classNamestringAdditional Tailwind classes, merged with the component's defaults via cn().
ComboboxItemAn individual option.
PropTypeDefaultDescription
valuestringThe value this item represents.
ComboboxEmptyRendered when no items match the query.
PropTypeDefaultDescription
classNamestringAdditional Tailwind classes, merged with the component's defaults via cn().
ComboboxTriggerOptional Select-style button trigger. Use instead of `ComboboxInput` when you want a closed dropdown that opens on click rather than a typeahead-first input.
PropTypeDefaultDescription
classNamestringAdditional Tailwind classes, merged with the component's defaults via cn().

Built on Base UI Combobox. The default pattern is typeahead-first: `ComboboxInput` is the visible control and filters items as the user types. Use `ComboboxTrigger` only for a Select-style closed state.

All components also accept standard HTML attributes for their root element (e.g. `id`, `aria-*`, `data-*`, event handlers) and forward `ref` where applicable.

Source

The full implementation of components/ui/combobox.tsx is below — copy it into your project and own it. Some components import the cn helper from lib/utils or other primitives; copy those too.

tsx
"use client";

import { cn } from "@/lib/utils";
import { Combobox as BaseCombobox } from "@base-ui-components/react/combobox";
import { Check, ChevronsUpDown } from "lucide-react";
import type { ComponentPropsWithoutRef } from "react";

export const Combobox = BaseCombobox.Root;

export function ComboboxTrigger({
  className,
  children,
  ...props
}: ComponentPropsWithoutRef<typeof BaseCombobox.Trigger>) {
  return (
    <BaseCombobox.Trigger
      className={cn(
        "flex h-9 w-full items-center justify-between rounded-md border border-border bg-bg px-3 py-2",
        "text-sm text-fg shadow-sm",
        "hover:bg-bg-subtle focus-visible:outline-1 focus-visible:outline-offset-0 focus-visible:outline-accent",
        "disabled:pointer-events-none disabled:opacity-50",
        "data-[popup-open]:outline-2 data-[popup-open]:outline-offset-2 data-[popup-open]:outline-accent",
        className,
      )}
      {...props}
    >
      {children ?? (
        <>
          <BaseCombobox.Value>
            {(v: unknown) => (v != null ? String(v) : "Select…")}
          </BaseCombobox.Value>
          <BaseCombobox.Icon>
            <ChevronsUpDown className="h-4 w-4 opacity-50" />
          </BaseCombobox.Icon>
        </>
      )}
    </BaseCombobox.Trigger>
  );
}

export function ComboboxInput({
  className,
  ...props
}: ComponentPropsWithoutRef<typeof BaseCombobox.Input>) {
  return (
    <BaseCombobox.Input
      className={cn(
        "flex h-9 w-full rounded-md border border-border bg-bg px-3 py-2",
        "text-sm text-fg shadow-sm placeholder:text-fg-subtle",
        "focus-visible:outline-1 focus-visible:outline-offset-0 focus-visible:outline-accent",
        "disabled:pointer-events-none disabled:opacity-50",
        className,
      )}
      {...props}
    />
  );
}

export function ComboboxContent({
  className,
  sideOffset = 4,
  ...props
}: ComponentPropsWithoutRef<typeof BaseCombobox.Popup> & { sideOffset?: number }) {
  return (
    <BaseCombobox.Portal>
      <BaseCombobox.Positioner sideOffset={sideOffset} className="z-50">
        <BaseCombobox.Popup
          className={cn(
            "max-h-[18rem] w-(--anchor-width) overflow-y-auto overscroll-contain rounded-md border border-border bg-surface-elevated shadow-md",
            "data-[starting-style]:opacity-0 data-[starting-style]:scale-95",
            "data-[ending-style]:opacity-0 data-[ending-style]:scale-95",
            "transition-all duration-150",
            className,
          )}
          {...props}
        />
      </BaseCombobox.Positioner>
    </BaseCombobox.Portal>
  );
}

export function ComboboxList({
  className,
  ...props
}: ComponentPropsWithoutRef<typeof BaseCombobox.List>) {
  return <BaseCombobox.List className={cn("p-1", className)} {...props} />;
}

export function ComboboxItem({
  className,
  children,
  ...props
}: ComponentPropsWithoutRef<typeof BaseCombobox.Item>) {
  return (
    <BaseCombobox.Item
      className={cn(
        "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm text-fg outline-none",
        "data-[highlighted]:bg-bg-muted data-[highlighted]:text-fg",
        "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
        className,
      )}
      {...props}
    >
      <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
        <BaseCombobox.ItemIndicator>
          <Check className="h-3.5 w-3.5" />
        </BaseCombobox.ItemIndicator>
      </span>
      {children}
    </BaseCombobox.Item>
  );
}

export function ComboboxEmpty({
  className,
  ...props
}: ComponentPropsWithoutRef<typeof BaseCombobox.Empty>) {
  return (
    <BaseCombobox.Empty
      className={cn("py-6 text-center text-sm text-fg-muted empty:hidden", className)}
      {...props}
    />
  );
}

export function ComboboxGroup(props: ComponentPropsWithoutRef<typeof BaseCombobox.Group>) {
  return <BaseCombobox.Group {...props} />;
}

export function ComboboxGroupLabel({
  className,
  ...props
}: ComponentPropsWithoutRef<typeof BaseCombobox.GroupLabel>) {
  return (
    <BaseCombobox.GroupLabel
      className={cn("px-2 py-1.5 text-xs font-semibold text-fg-muted", className)}
      {...props}
    />
  );
}

JavaFX

Ships in the PRIZM JavaFX library for thick-client C3 apps as PrizmCombobox<T> (extends Region (custom: search field + filtered popup list)). Run the gallery to see it natively.

java
import design.prizm.fx.controls.PrizmCombobox<T>;

PrizmCombobox()
PrizmCombobox(ObservableList<T> items)
PropTypeDefaultDescription
getSourceItems() → ObservableList<T>The backing options — add / remove here.
valueObjectProperty<T>The committed value (what the check marks); changes only on Enter / click.
setPromptText(String) → voidPlaceholder for the search field.

A custom control (not the stock editable ComboBox, whose arrow-keys mutate the value). A search field filters a popup list; the single highlight (selected row) follows keyboard AND hover, while the check marks only the committed value and never moves during navigation. Enter / click commits. The non-editable picker is PrizmSelect. Mirrors components/ui/combobox.tsx.