# Field: Native Select (category: selection)

URL: https://docs.forms.saastro.io/docs/native-select

<FieldPreview name="native-select" description="Interactive demo of native select field" />

## Overview

The native select field uses the browser's built-in `<select>` element. It's ideal when you need maximum compatibility, mobile-friendly dropdowns, or when the styled [Select](/docs/select) is overkill. The first option always renders with an empty value and shows the `placeholder` text.

> **Default placeholder.** When `placeholder` is omitted, the first option falls back to the built-in English default `'Enter a value...'`. Set a `placeholder` per field or override the defaults globally with `setDefaultMessages` — see the [Internationalization guide](/docs/i18n).

## Usage

### Basic Native Select

```tsx

const config = FormBuilder.create('form')
  .addField('country', (f) =>
    f
      .type('native-select')
      .label('Country')
      .placeholder('Select a country')
      .options([
        { label: 'United States', value: 'us' },
        { label: 'Canada', value: 'ca' },
        { label: 'Mexico', value: 'mx' },
      ])
      .required('Please select a country'),
  )
  .addStep('main', ['country'])
  .build();
```

### With Default Value

```tsx
.addField('language', (f) =>
  f.type('native-select')
    .label('Language')
    .options([
      { label: 'English', value: 'en' },
      { label: 'Spanish', value: 'es' },
      { label: 'French', value: 'fr' },
    ])
    .value('en')
    .required()
)
```

### With Many Options

Options render as a flat list — `<optgroup>` grouping is not supported.

```tsx
.addField('timezone', (f) =>
  f.type('native-select')
    .label('Timezone')
    .options([
      { label: 'America/New_York', value: 'america-new-york' },
      { label: 'America/Los_Angeles', value: 'america-la' },
      { label: 'Europe/London', value: 'europe-london' },
      { label: 'Europe/Paris', value: 'europe-paris' },
      { label: 'Asia/Tokyo', value: 'asia-tokyo' },
    ])
    .required()
)
```

### JSON Configuration

```json
{
  "type": "native-select",
  "label": "Country",
  "placeholder": "Select a country",
  "options": [
    { "label": "United States", "value": "us" },
    { "label": "Canada", "value": "ca" },
    { "label": "Mexico", "value": "mx" }
  ],
  "schema": { "required": true }
}
```

## Props

| Prop          | Type                                                  | Default | Description                |
| ------------- | ----------------------------------------------------- | ------- | -------------------------- |
| `type`        | `'native-select'`                                     | -       | Field type (required)      |
| `label`       | `string`                                              | -       | Label text                 |
| `placeholder` | `string`                                              | -       | Placeholder option text    |
| `helperText`  | `string`                                              | -       | Help text below field      |
| `options`     | `Option[]`                                            | -       | Array of options (required) |
| `schema`      | `z.ZodType \| ValidationRules`                        | -       | Validation: a Zod schema or serializable JSON rules (required — fluent methods like `.required()` populate it for you) |
| `value`       | `string`                                              | -       | Initial selected value     |
| `size`        | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'`                | -       | Declared but not applied by the native-select renderer |
| `columns`     | `Partial<Record<Breakpoint, number>>`                 | -       | Column span (1–12) per breakpoint, in manual layout |
| `disabled`    | `boolean \| function \| ConditionGroup`               | `false` | Disable the select         |
| `hidden`      | `boolean \| function \| ConditionGroup \| Responsive` | `false` | Hide the field             |

## Native Select vs Styled Select

| Use Native Select     | Use [Select](/docs/select) |
| --------------------- | -------------------------- |
| Mobile-first apps     | Custom styling needed      |
| Maximum compatibility | Rich interactions          |
| Plain text options    | Options with icons         |

## Validation

### Required Selection

```tsx
.addField('size', (f) =>
  f.type('native-select')
    .label('Size')
    .options([
      { label: 'Small', value: 's' },
      { label: 'Medium', value: 'm' },
      { label: 'Large', value: 'l' },
    ])
    .required('Please select a size')
)
```

## Styling

### Custom Classes

```tsx
.addField('country', (f) =>
  f.type('native-select')
    .label('Country')
    .options([
      { label: 'United States', value: 'us' },
      { label: 'Canada', value: 'ca' },
    ])
    .required()
    .classNames({
      wrapper: 'bg-muted/30 p-3 rounded-lg',
      input: 'border-primary bg-background',
      label: 'text-sm font-medium',
      error: 'text-destructive text-sm',
    })
)
```

### Responsive Layout

Per-field `columns` apply when the form uses manual layout — see the [Layout guide](/docs/layout).

```tsx
.addField('language', (f) =>
  f.type('native-select')
    .label('Language')
    .options([
      { label: 'English', value: 'en' },
      { label: 'Spanish', value: 'es' },
    ])
    .optional()
    .columns({ default: 12, md: 6, lg: 4 })
)
```

### JSON Styling

```json
{
  "type": "native-select",
  "label": "Country",
  "options": [
    { "label": "United States", "value": "us" },
    { "label": "Canada", "value": "ca" }
  ],
  "schema": { "required": true },
  "wrapper_className": "bg-muted/30 p-3 rounded-lg",
  "input_className": "border-primary",
  "label_className": "text-sm font-medium",
  "columns": { "default": 12, "md": 6 }
}
```

## Related Fields

- [Select](/docs/select) - Styled select with custom trigger and items
- [Combobox](/docs/combobox) - Searchable select
- [Radio](/docs/radio) - Visible options

## Accessibility

- Native `<select>` element for full accessibility
- Works with all assistive technologies
- Keyboard navigation built-in
- Mobile-friendly with native picker UI
