# Field: Command (category: selection)

URL: https://docs.forms.saastro.io/docs/command

<FieldPreview name="command" description="Interactive demo of command field" />

## Overview

The command field is a searchable dropdown built on [cmdk](https://cmdk.paco.me/). It currently renders **the exact same popover UI as [combobox](/docs/combobox)**: a button trigger that opens a popover containing a search input and a filterable option list. Selecting the already-selected option clears the value.

`command` exists as a distinct type string, but today there is no visual or behavioral difference from `combobox` — both accept the same props and require the same components. Use whichever type name reads better in your config.

## Usage

### Basic Command

```tsx

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

### With Icons

Options accept an optional `icon` rendered before the label:

```tsx

.addField('framework', (f) =>
  f.type('command')
    .label('Framework')
    .options([
      { label: 'React', value: 'react', icon: <Globe /> },
      { label: 'Vue', value: 'vue', icon: <Zap /> },
      { label: 'Svelte', value: 'svelte', icon: <Palette /> },
    ])
)
```

### Custom Search and Empty Text

```tsx
.addField('country', (f) =>
  f.type('command')
    .label('Country')
    .placeholder('Select a country...')
    .searchPlaceholder('Type a country name...')
    .emptyText('No matching country.')
    .options([
      { label: 'Argentina', value: 'ar' },
      { label: 'Spain', value: 'es' },
      { label: 'United States', value: 'us' },
      // ...
    ])
    .required()
)
```

### JSON Configuration

```json
{
  "type": "command",
  "label": "Framework",
  "placeholder": "Select a framework...",
  "searchPlaceholder": "Search frameworks...",
  "emptyText": "No option found.",
  "options": [
    { "label": "React", "value": "react" },
    { "label": "Vue", "value": "vue" },
    { "label": "Svelte", "value": "svelte" }
  ],
  "schema": { "required": true }
}
```

## Props

| Prop                | Type                                                  | Default                  | Description                            |
| ------------------- | ----------------------------------------------------- | ------------------------ | -------------------------------------- |
| `type`              | `'command'`                                           | -                        | Field type (required)                  |
| `label`             | `string`                                              | -                        | Label text                             |
| `options`           | `Option[]`                                            | -                        | Array of `{ label, value, icon? }`     |
| `placeholder`       | `string`                                              | `'Enter a value...'`     | Trigger text when no value is selected |
| `searchPlaceholder` | `string`                                              | `'Search...'`            | Placeholder in the search input        |
| `emptyText`         | `string`                                              | `'No option found.'`     | Text shown when search has no matches  |
| `helperText`        | `string`                                              | -                        | Help text below field                  |
| `value`             | `string`                                              | -                        | Default selected value                 |
| `columns`           | `Partial<Record<Breakpoint, number>>`                 | -                        | Grid columns by breakpoint             |
| `disabled`          | `boolean \| function \| ConditionGroup`               | `false`                  | Disable the field                      |
| `hidden`            | `boolean \| function \| ConditionGroup \| Responsive` | `false`                  | Hide the field                         |

> The fallback `placeholder` comes from the package's built-in English defaults. All default UI strings can be overridden — globally with `setDefaultMessages` or per locale; see the [i18n guide](/docs/i18n).

## Required Components

Because `command` renders the same popover UI as `combobox`, it needs the popover and button components too — not just the cmdk ones. Your component registry must provide:

- `Command`, `CommandInput`, `CommandList`, `CommandEmpty`, `CommandGroup`, `CommandItem`
- `Popover`, `PopoverTrigger`, `PopoverContent`, `Button`
- `FormField`, `FormControl`, `Field`, `FieldDescription`, `FieldError`

If any of these are missing, the field renders a "missing component" fallback instead. Install the UI primitives with shadcn:

```bash
npx shadcn@latest add command popover button
```

See [Component System](/docs/components) for how to register them.

## Validation

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

## Related Fields

- [Combobox](/docs/combobox) - Renders identically; same props and components
- [Select](/docs/select) - Standard dropdown without search
- [Native Select](/docs/native-select) - Browser native select

## Accessibility

- Built on cmdk (Command Menu)
- Trigger button exposes `role="combobox"` and `aria-expanded`
- Full keyboard navigation; type to filter
- Screen reader announcements and focus management
