> ## Documentation Index
> Fetch the complete documentation index at: https://docs.overflow.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Select

> A dropdown input for merchant-defined choices.

The `select` custom element renders a `<select>` populated from a static option list. Use it for merchant-defined enumerated choices.

## Factory

```typescript theme={null}
overflow.select<TValue extends string>(
  options: CustomSelectElementOptions<TValue>,
): CustomSelectElement<TValue>
```

## Example

```javascript theme={null}
const state = overflow.select({
  name: 'state',
  label: 'State',
  placeholder: 'Select a state',
  required: true,
  options: [
    { label: 'New York', value: 'NY' },
    { label: 'California', value: 'CA' },
  ] as const,
});

state.on('onChange', ({ value }) => console.log(value));
state.mount('#state');
```

## Options

| Key                                                                 | Type                                        | Default                                                      | Notes                                                               |
| ------------------------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------- |
| `elementType`                                                       | `'select'`                                  | required                                                     | Discriminant when configured inside Checkout.                       |
| `name`                                                              | `string`                                    | required                                                     | Unique per `Overflow` instance.                                     |
| `label`                                                             | `string`                                    | required                                                     | Renders as `<label>`.                                               |
| `options`                                                           | `CustomSelectOption[]`                      | required                                                     | Minimum two entries; empty-string `value` is reserved.              |
| `placeholder`                                                       | `string`                                    | none                                                         | When set, renders a selectable empty option at the top of the list. |
| `defaultValue`                                                      | `TValue`                                    | none                                                         | Must match one of `options[].value`.                                |
| `required`                                                          | `boolean`                                   | `false`                                                      | Empty selection rejected by the built-in check.                     |
| `validate`                                                          | `(value: string \| null) => string \| null` | none                                                         | Overrides the built-in `required` check.                            |
| `disabled`, `readOnly`, `id`, `ariaLabel`, `locale`, `autocomplete` | shared                                      | see [reference](/payment-elements/elements/custom/reference) |                                                                     |

### `CustomSelectOption`

```typescript theme={null}
type CustomSelectOption<TValue extends string = string> = {
  label: string;
  value: TValue;
};
```

### Typed option lists

Pass `options` `as const` to narrow `defaultValue` to the union of supplied values:

```typescript theme={null}
overflow.select({
  name: 'state',
  label: 'State',
  options: [
    { label: 'New York', value: 'NY' },
    { label: 'California', value: 'CA' },
  ] as const,
  defaultValue: 'TX', // Type error: not 'NY' | 'CA'
});
```

### Minimum two options

The SDK refuses to mount a `<select>` with fewer than two entries. Passing `options: []` or `options: [{...}]` logs a console warning and returns a no-op handle. Every subsequent call on that handle is silently ignored.

### Reserved value

The empty string `''` is reserved for the placeholder slot. Any merchant-supplied `options[].value === ''` triggers a console warning and a no-op handle. Use `placeholder` when you need a "none" affordance.

### Initial selection

The initial selected value resolves in this order at mount:

1. `defaultValue`, when supplied and it matches one of `options[].value`.
2. Otherwise, when `placeholder` is set, the placeholder slot renders selected and the emitted value on first interaction is `null`.
3. Otherwise, `options[0]` is pre-selected and the emitted value on mount equals `options[0].value`.

A `defaultValue` that does not match any option logs a console warning and falls through to step 2 or 3.

### `required` behavior

With `required: true` and no `placeholder`, the field never trips the empty check because a real selection is always present from mount. Pair `required: true` with `placeholder` to force shoppers to make an explicit choice.

## Value

```typescript theme={null}
type CustomSelectValue<TValue extends string> = TValue | null;
```

The emitted value is exactly the chosen option's `value` string. Selecting the placeholder slot emits `null`. Submit forwards the same shape.

## Inside Checkout

```javascript theme={null}
overflow.checkout({
  paymentMethods: ['card'],
  customElements: {
    state: {
      elementType: 'select',
      label: 'State',
      options: [
        { label: 'New York', value: 'NY' },
        { label: 'California', value: 'CA' },
      ],
    },
  },
});
```

## See also

* [Custom elements introduction](/payment-elements/elements/custom/introduction)
* [Custom reference](/payment-elements/elements/custom/reference)
