Propel

Combobox Field

A labeled multi-select combobox with title and description above a closed trigger, an overlay panel of searchable checkbox items, and helper or error text below.

Filter the deployment region.

Helper text

Show code
import { ComboboxField } from "@makeplane/propel/components/combobox-field";
import { Icon } from "@makeplane/propel/components/icon";
import { Plus } from "lucide-react";

const REGIONS = ["us-central-1", "us-east-1", "eu-central-1", "ap-west-1"];

export default function BasicDemo() {
  return (
    <ComboboxField
      name="region"
      label="Region"
      description="Filter the deployment region."
      hint="Helper text"
      required
      size="lg"
      items={REGIONS}
      placeholder="Select label"
      empty="No regions found"
      icon={<Icon icon={Plus} tint="placeholder" />}
    />
  );
}

Installation

import { ComboboxField } from "@makeplane/propel/components/combobox-field";

Usage

import { ComboboxField } from "@makeplane/propel/components/combobox-field";
import { Icon } from "@makeplane/propel/components/icon";
import { Plus } from "lucide-react";

const REGIONS = ["us-central-1", "us-east-1", "eu-central-1", "ap-west-1"];

export default function BasicDemo() {
  return (
    <ComboboxField
      name="region"
      label="Region"
      description="Filter the deployment region."
      hint="Helper text"
      required
      size="lg"
      items={REGIONS}
      placeholder="Select label"
      empty="No regions found"
      icon={<Icon icon={Plus} tint="placeholder" />}
    />
  );
}

Examples

Sizes

size steps the label, description, and helper text together with the trigger’s own scale.

Filter the deployment region.

Helper text

Filter the deployment region.

Helper text

Filter the deployment region.

Helper text

Show code
import { ComboboxField } from "@makeplane/propel/components/combobox-field";

const REGIONS = ["us-central-1", "us-east-1", "eu-central-1", "ap-west-1"];
const SIZES = ["lg", "xl", "2xl"] as const;

export default function SizesDemo() {
  return (
    <div className="flex flex-col gap-4">
      {SIZES.map((size) => (
        <ComboboxField
          key={size}
          name={`region-${size}`}
          label={size}
          description="Filter the deployment region."
          hint="Helper text"
          size={size}
          items={REGIONS}
          placeholder="Select label"
          empty="No regions found"
        />
      ))}
    </div>
  );
}

Invalid

Setting error marks the field invalid, recoloring the trigger border. The error replaces helper text below the control; the description above the control stays.

Choose a deployment region.
Show code
import { ComboboxField } from "@makeplane/propel/components/combobox-field";

const REGIONS = ["us-central-1", "us-east-1", "eu-central-1", "ap-west-1"];

export default function InvalidDemo() {
  return (
    <ComboboxField
      name="region"
      label="Region"
      error="Choose a deployment region."
      size="lg"
      items={REGIONS}
      placeholder="Select label"
      empty="No regions found"
    />
  );
}

Disabled

Filter the deployment region.

Helper text

Show code
import { ComboboxField } from "@makeplane/propel/components/combobox-field";
import { Icon } from "@makeplane/propel/components/icon";
import { Plus } from "lucide-react";

const REGIONS = ["us-central-1", "us-east-1", "eu-central-1", "ap-west-1"];

export default function DisabledDemo() {
  return (
    <ComboboxField
      name="region"
      label="Region"
      description="Filter the deployment region."
      hint="Helper text"
      size="lg"
      disabled
      items={REGIONS}
      placeholder="Select label"
      empty="No regions found"
      icon={<Icon icon={Plus} tint="placeholder" />}
    />
  );
}

API Reference

ComboboxField

Ready-to-use combobox field: a closed trigger, overlay search, checkbox rows, and helper/error text.

PropTypeDefaultDescription
empty(required)ReactNodeMessage rendered when no item matches.
items(required)readonly Value[]Items rendered in the popup.
label(required)stringVisible field label.
size(required)"2xl" | "lg" | "xl"Label and helper text size.
autoCompletestringProvides a hint to the browser for autofill. @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete
autoHighlightbooleanfalseWhether the first matching item is highlighted automatically while filtering.
highlightItemOnHoverbooleantrueWhether moving the pointer over items should highlight them. Disabling this prop allows CSS `:hover` to be differentiated from the `:focus` (`data-highlighted`) state.
itemToStringLabel((itemValue: Value) => string)When the item values are objects (`<Combobox.Item value={object}>`), this function converts the object value to a string representation for display in the input. If the shape of the object is `{ value, label }`, the label will be used automatically without needing to specify this prop.
itemToStringValue((itemValue: Value) => string)When the item values are objects (`<Combobox.Item value={object}>`), this function converts the object value to a string representation for form submission. If the shape of the object is `{ value, label }`, the value will be used automatically without needing to specify this prop.
isItemEqualToValue((itemValue: Value, value: Value) => boolean)Custom comparison logic used to determine if a combobox item value matches the current selected value. Useful when item values are objects without matching referentially. Defaults to `Object.is` comparison.
actionsRefRefObject<Actions | null>A ref to imperative actions. - `unmount`: Manually unmounts the combobox. Call this after any externally controlled closing animation finishes.
onOpenChange((open: boolean, eventDetails: ChangeEventDetails) => void)Event handler called when the popup is opened or closed.
onInputValueChange((inputValue: string, eventDetails: ChangeEventDetails) => void)Event handler called when the input value changes.
onItemHighlighted((highlightedValue: Value, eventDetails: HighlightEventDetails) => void)Callback fired when an item is highlighted or unhighlighted. Receives the highlighted item value (or `undefined` if no item is highlighted) and event details with a `reason` property describing why the highlight changed. The `reason` can be: - `'keyboard'`: the highlight changed due to keyboard navigation. - `'pointer'`: the highlight changed due to pointer hovering. - `'none'`: the highlight changed programmatically.
defaultValueValue[] | nullThe uncontrolled selected value of the combobox when it's initially rendered. To render a controlled combobox, use the `value` prop instead.
valueValue[] | nullThe selected value of the combobox. Use when controlled.
variant"neutral" | "ghost""neutral"Frame look. `neutral` is the bordered field surface; `ghost` is borderless. Invalid on ghost has no trigger chrome — the danger cue is the helper text below.
descriptionReactNodeSupporting text shown below the label.
trailingReactNodeDecorative trailing glyph inside the trigger. Omit it to show a chevron.
iconReactNodeDecorative leading element at the inline-start, e.g. `<Icon icon={Plus} tint="placeholder" />`.
errorReactNodeError text shown below the control.
hintReactNodeHelper text shown below the control. Replaced by `error` when an error is set.
placeholderstringShown in the trigger while nothing is selected.
searchLabelstringSearchAccessible name and placeholder for the panel search field.
selectAllLabelstringSelect allLabel for the sticky row that selects or clears every item. Acts on the whole `items` list, NOT on whatever the panel search has filtered down to — so pressing it while a query is active also selects the values the query hid, and the row's checked / indeterminate state likewise reflects `items` rather than the visible subset. That is deliberate ("all" means all), but it is the surprising half of the behaviour, so give the row a label that says so if a screen's search is prominent.
onValueChange((value: Value[], details?: ChangeEventDetails) => void)Called when the selection changes. Item presses pass Base UI's event `details`; Select all passes only the next value.