Combobox

A searchable select. Click the trigger to open a popup with a built-in search input that filters the list as you type.

Basic

Show code
Hide code
import { Combobox, type ComboboxOption } from '@mylighthouse/prism-react';
import { useState } from 'react';

export default function BasicExample(): React.JSX.Element {
  const [value, setValue] = useState<string | null>(null);

  const options = [
    { label: 'Amsterdam', value: 'amsterdam' },
    { label: 'Athens', value: 'athens' },
    { label: 'Barcelona', value: 'barcelona' },
    { label: 'Berlin', value: 'berlin' },
    { label: 'Brussels', value: 'brussels' },
    { label: 'Budapest', value: 'budapest' },
    { label: 'Copenhagen', value: 'copenhagen' },
    { label: 'Dublin', value: 'dublin' },
    { label: 'Lisbon', value: 'lisbon' },
    { label: 'London', value: 'london' },
    { label: 'Madrid', value: 'madrid' },
    { label: 'Milan', value: 'milan' },
    { label: 'Paris', value: 'paris' },
    { label: 'Prague', value: 'prague' },
    { label: 'Rome', value: 'rome' },
    { label: 'Stockholm', value: 'stockholm' },
    { label: 'Vienna', value: 'vienna' },
    { label: 'Warsaw', value: 'warsaw' },
  ];

  return (
    <Combobox onChange={setValue} options={options} value={value}>
      <Combobox.Trigger placeholder="Select a city…" />
      <Combobox.Menu>
        {(option: ComboboxOption<string>) => (
          <Combobox.Option key={option.value} value={option.value}>
            {option.label}
          </Combobox.Option>
        )}
      </Combobox.Menu>
    </Combobox>
  );
}

Custom content

Pass any React content as children to Combobox.Option, the text is extracted from that content for search filtering. To customise what appears in the trigger for the selected value, pass a render function as children to Combobox.Trigger.

Show code
Hide code
import { Badge, Combobox, Icon } from '@mylighthouse/prism-react';
import { useState } from 'react';

type City = { country: string; label: string; value: string };

const options: City[] = [
  { label: 'Amsterdam', value: 'amsterdam', country: 'NL' },
  { label: 'Barcelona', value: 'barcelona', country: 'ES' },
  { label: 'London', value: 'london', country: 'GB' },
  { label: 'Paris', value: 'paris', country: 'FR' },
  { label: 'Rome', value: 'rome', country: 'IT' },
];

export default function CustomTriggerExample(): React.JSX.Element {
  const [value, setValue] = useState<string | null>(null);

  return (
    <Combobox onChange={setValue} options={options} value={value}>
      <Combobox.Trigger placeholder="Select a city…">
        {(selectedValue) => {
          const city = options.find((o) => o.value === selectedValue);
          return city ? (
            <span style={{ alignItems: 'center', display: 'flex', gap: '8px' }}>
              <Icon aria-hidden="true" name="location-pin" size="small" />
              {city.label}
            </span>
          ) : null;
        }}
      </Combobox.Trigger>
      <Combobox.Menu>
        {(option: City) => (
          <Combobox.Option key={option.value} value={option.value}>
            <span style={{ alignItems: 'center', display: 'flex', gap: '8px' }}>
              <Icon aria-hidden="true" name="location-pin" size="small" />
              {option.label}
            </span>
            <Badge isSmall>{option.country}</Badge>
          </Combobox.Option>
        )}
      </Combobox.Menu>
    </Combobox>
  );
}

Validation states

Use hasError for critical validation failures and hasWarning for non-blocking issues. Pass disabled to prevent all interaction.

Show code
Hide code
import { Combobox, type ComboboxOption } from '@mylighthouse/prism-react';
import { useState } from 'react';

const options: ComboboxOption<string>[] = [
  { label: 'Amsterdam', value: 'amsterdam' },
  { label: 'Barcelona', value: 'barcelona' },
  { label: 'London', value: 'london' },
  { label: 'Paris', value: 'paris' },
  { label: 'Rome', value: 'rome' },
];

const optionsWithDisabled: ComboboxOption<string>[] = [
  { label: 'Amsterdam', value: 'amsterdam' },
  { label: 'Barcelona', value: 'barcelona', disabled: true },
  { label: 'London', value: 'london' },
  { label: 'Paris', value: 'paris', disabled: true },
  { label: 'Rome', value: 'rome' },
];

export default function ValidationStatesExample(): React.JSX.Element {
  const [errorValue, setErrorValue] = useState<string | null>('amsterdam');
  const [warningValue, setWarningValue] = useState<string | null>('amsterdam');
  const [disabledValue] = useState<string | null>('amsterdam');
  const [disabledOptionsValue, setDisabledOptionsValue] = useState<
    string | null
  >(null);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
      <Combobox
        hasError
        onChange={setErrorValue}
        options={options}
        value={errorValue}
      >
        <Combobox.Trigger placeholder="Error state" />
        <Combobox.Menu>
          {(option: ComboboxOption<string>) => (
            <Combobox.Option key={option.value} value={option.value}>
              {option.label}
            </Combobox.Option>
          )}
        </Combobox.Menu>
      </Combobox>

      <Combobox
        hasWarning
        onChange={setWarningValue}
        options={options}
        value={warningValue}
      >
        <Combobox.Trigger placeholder="Warning state" />
        <Combobox.Menu>
          {(option: ComboboxOption<string>) => (
            <Combobox.Option key={option.value} value={option.value}>
              {option.label}
            </Combobox.Option>
          )}
        </Combobox.Menu>
      </Combobox>

      <Combobox disabled options={options} value={disabledValue}>
        <Combobox.Trigger placeholder="Disabled state" />
        <Combobox.Menu>
          {(option: ComboboxOption<string>) => (
            <Combobox.Option key={option.value} value={option.value}>
              {option.label}
            </Combobox.Option>
          )}
        </Combobox.Menu>
      </Combobox>

      <Combobox
        onChange={setDisabledOptionsValue}
        options={optionsWithDisabled}
        value={disabledOptionsValue}
      >
        <Combobox.Trigger placeholder="Disabled options" />
        <Combobox.Menu>
          {(option: ComboboxOption<string>) => (
            <Combobox.Option
              disabled={option.disabled}
              key={option.value}
              value={option.value}
            >
              {option.label}
            </Combobox.Option>
          )}
        </Combobox.Menu>
      </Combobox>
    </div>
  );
}

Small

Use isSmall for a more compact control.

Show code
Hide code
import { Combobox, type ComboboxOption } from '@mylighthouse/prism-react';
import { useState } from 'react';

const options = [
  { label: 'Amsterdam', value: 'amsterdam' },
  { label: 'Barcelona', value: 'barcelona' },
  { label: 'London', value: 'london' },
  { label: 'Paris', value: 'paris' },
  { label: 'Rome', value: 'rome' },
];

export default function SmallExample(): React.JSX.Element {
  const [value, setValue] = useState<string | null>(null);

  return (
    <Combobox isSmall onChange={setValue} options={options} value={value}>
      <Combobox.Trigger placeholder="Select a city…" />
      <Combobox.Menu>
        {(option: ComboboxOption<string>) => (
          <Combobox.Option key={option.value} value={option.value}>
            {option.label}
          </Combobox.Option>
        )}
      </Combobox.Menu>
    </Combobox>
  );
}

API Reference

Combobox

Name Default Type Description
options * -- ComboboxOption<Value>[] --
defaultValue -- Value --
disabled -- boolean --
hasError -- boolean --
hasWarning -- boolean --
isSmall -- boolean --
name -- string --
onChange -- (value: Value) => void --
unsafe_open -- boolean Do not use this prop in production. Only used for testing and documentation purposes.
value -- Value --

Combobox.Trigger

Name Default Type Description
aria-label -- string --
id -- string --
placeholder -- string --

Combobox.Menu

Name Default Type Description
placeholder -- string --
searchLabel -- string Accessible label for the search input. Defaults to "Search". Override for localisation or context-specific labels.

Combobox.Option

Name Default Type Description
value * -- Value --
disabled -- boolean --