S
Selection Field

Combobox

Searchable dropdown with autocomplete for finding options quickly.

stable
combobox autocomplete search select

Interactive demo of combobox field

Type to search and filter options

/**
 * Combobox Field Demo - Interactive examples of combobox fields
 */

import { Form, FormBuilder } from '@saastro/forms';

import { FormProvider } from '@/components/FormProvider';
import { TooltipProvider } from '@/components/ui/tooltip';

const config = FormBuilder.create('combobox-demo')
  .layout('manual')
  .columns(12)
  .addField('framework', (f) =>
    f
      .type('combobox')
      .label('Framework')
      .placeholder('Search frameworks...')
      .helperText('Type to search and filter options')
      .options([
        { label: 'React', value: 'react' },
        { label: 'Vue', value: 'vue' },
        { label: 'Angular', value: 'angular' },
        { label: 'Svelte', value: 'svelte' },
        { label: 'Solid', value: 'solid' },
        { label: 'Qwik', value: 'qwik' },
        { label: 'Preact', value: 'preact' },
        { label: 'Lit', value: 'lit' },
      ])
      .required('Please select a framework')
      .columns({ default: 12, md: 6 }),
  )
  .addField('language', (f) =>
    f
      .type('combobox')
      .label('Programming Language')
      .placeholder('Search languages...')
      .options([
        { label: 'TypeScript', value: 'typescript' },
        { label: 'JavaScript', value: 'javascript' },
        { label: 'Python', value: 'python' },
        { label: 'Rust', value: 'rust' },
        { label: 'Go', value: 'go' },
        { label: 'Java', value: 'java' },
        { label: 'C#', value: 'csharp' },
        { label: 'Ruby', value: 'ruby' },
      ])
      .required()
      .columns({ default: 12, md: 6 }),
  )
  .addField('country', (f) =>
    f
      .type('combobox')
      .label('Country')
      .placeholder('Search countries...')
      .options([
        { label: 'Argentina', value: 'ar' },
        { label: 'Australia', value: 'au' },
        { label: 'Brazil', value: 'br' },
        { label: 'Canada', value: 'ca' },
        { label: 'China', value: 'cn' },
        { label: 'France', value: 'fr' },
        { label: 'Germany', value: 'de' },
        { label: 'India', value: 'in' },
        { label: 'Japan', value: 'jp' },
        { label: 'Mexico', value: 'mx' },
        { label: 'Spain', value: 'es' },
        { label: 'United Kingdom', value: 'uk' },
        { label: 'United States', value: 'us' },
      ])
      .required()
      .columns({ default: 12 }),
  )
  .addStep('main', ['framework', 'language', 'country'])
  .build();

export default function ComboboxDemo() {
  const handleSubmit = (data: Record<string, unknown>) => {
    console.log('Form submitted:', data);
    alert('Form submitted! Check console for data.');
  };

  return (
    <TooltipProvider>
      <FormProvider>
        <Form config={config} onSubmit={handleSubmit} className="space-y-4" />
      </FormProvider>
    </TooltipProvider>
  );
}

Overview

The combobox field combines a text input with a dropdown list, allowing users to search and filter options. It’s ideal for long lists where users need to find options quickly.

Usage

Basic Combobox

import { FormBuilder } from '@saastro/forms';

const config = FormBuilder.create('form')
  .addField('framework', (f) =>
    f
      .type('combobox')
      .label('Framework')
      .placeholder('Search frameworks...')
      .options([
        { label: 'React', value: 'react' },
        { label: 'Vue', value: 'vue' },
        { label: 'Angular', value: 'angular' },
        { label: 'Svelte', value: 'svelte' },
        { label: 'Solid', value: 'solid' },
        { label: 'Qwik', value: 'qwik' },
      ])
      .required('Please select a framework'),
  )
  .addStep('main', ['framework'])
  .build();

With Many Options

.addField('country', (f) =>
  f.type('combobox')
    .label('Country')
    .placeholder('Search countries...')
    .options([
      { label: 'Argentina', value: 'ar' },
      { label: 'Australia', value: 'au' },
      { label: 'Brazil', value: 'br' },
      { label: 'Canada', value: 'ca' },
      // ... many more
    ])
    .required()
)

JSON Configuration

{
  "type": "combobox",
  "label": "Framework",
  "placeholder": "Search frameworks...",
  "options": [
    { "label": "React", "value": "react" },
    { "label": "Vue", "value": "vue" },
    { "label": "Angular", "value": "angular" }
  ],
  "schema": { "required": true }
}

Props

PropTypeDefaultDescription
type'combobox'-Field type (required)
labelstring-Label text
placeholderstring-Search input placeholder
helperTextstring-Help text below field
optionsOption[]-Array of searchable options
valuestring-Default selected value
size'sm' | 'md' | 'lg''md'Input size variant
columnsPartial<Record<Breakpoint, number>>-Grid columns by breakpoint
disabledboolean | function | ConditionGroupfalseDisable the field
hiddenboolean | function | ConditionGroup | ResponsivefalseHide the field

Combobox vs Select

Use ComboboxUse Select
10+ optionsFewer options
Users know what they wantUsers browse options
Long lists (countries, etc.)Short curated lists
Typing is fasterScrolling is fine

Validation

Required Selection

.addField('timezone', (f) =>
  f.type('combobox')
    .label('Timezone')
    .options([...timezones])
    .required('Please select a timezone')
)

Styling

Custom Classes

.addField('country', (f) =>
  f.type('combobox')
    .label('Country')
    .options([...])
    .required()
    .classNames({
      wrapper: 'bg-muted/30 p-4 rounded-lg',
      input: 'border-2 border-primary/20',
      label: 'text-lg font-semibold',
      error: 'text-destructive text-sm',
    })
)

Size Variants

.addField('timezone', (f) =>
  f.type('combobox')
    .label('Timezone')
    .options([...])
    .size('lg')
)

Responsive Layout

.addField('country', (f) =>
  f.type('combobox')
    .label('Country')
    .options([...])
    .columns({ default: 12, md: 6 })
)

JSON Styling

{
  "type": "combobox",
  "label": "Country",
  "placeholder": "Search countries...",
  "wrapper_className": "bg-muted/30 p-4 rounded-lg",
  "input_className": "border-2 border-primary/20",
  "label_className": "text-lg font-semibold",
  "size": "lg",
  "columns": { "default": 12, "md": 6 }
}

Accessibility

  • Built on cmdk (Command Menu)
  • Full keyboard navigation
  • Type to filter
  • Screen reader announcements
  • Focus management