# Select
> Select is an input control that allows users to choose one option from a list.

<Callout variant="tip">

`Select` is just a lightweight wrapper around a [native HTML Select element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select).

Consider using [Single Select Menu](/components/forms/select-menu/single-select-menu) and/or [Multi Select Menu](/components/forms/select-menu/multi-select-menu) as a consistently styled and more powerful alternative.

</Callout>

## Import

```js
import { Select } from '@gemini-suite/vera-react';
```

## Examples

### Basic

```jsx
<Select
  aria-label="Select label"
  onChange={console.log}
  placeholder="Select option"
  options={[
    { value: 'option1', label: 'Option 1' },
    { value: 'option2', label: 'Option 2' },
    { value: 'option3', label: 'Option 3' }
  ]}
/>
```

### Controlled

`Select` is a [controlled component](https://reactjs.org/docs/forms.html#controlled-components), meaning that React state drives its value. You need to provide `value` and `onChange` properties to "make it work".

```jsx
() => {
  const [value, setValue] = React.useState('');

  return (
    <Flex flow="column" gap="spacingS">
      <Box>Value: {value}</Box>
      <Select
        value={value}
        onChange={setValue}
        aria-label="Input label"
        placeholder="Select option"
        options={[
          { value: 'option1', label: 'Option 1' },
          { value: 'option2', label: 'Option 2' },
          { value: 'option3', label: 'Option 3' }
        ]}
      />
    </Flex>
  );
};
```

### With Form Field

`Select` should be clearly labeled so it's obvious to users what are they choosing. Optionally, you may want to connect helper text and/or validation feedback message to the select.
Thus it is recommended to wrap select inputs with [Form Field](/components/forms/form-field) to create a consistent set of form fields that are accessible to screen reader users.

```jsx
() => {
  const [range, setRange] = React.useState('today');
  const [region, setRegion] = React.useState();

  return (
    <Flex flow="column">
      <FormField.Root as={Flex} flow="column">
        <FormField.Label>{'Date range'}</FormField.Label>
        <Select
          value={range}
          onChange={setRange}
          options={[
            { label: 'Today', value: 'today' },
            { label: 'Yesterday', value: 'yesterday' },
            { label: 'Last 7 days', value: 'lastWeek' }
          ]}
        />
      </FormField.Root>
      <FormField.Root
        as={Flex}
        flow="column"
        validationStatus={!region ? 'error' : undefined}
        isRequired
      >
        <FormField.Label>{'Region'}</FormField.Label>
        <Select
          value={region}
          onChange={setRegion}
          placeholder="Please select"
          options={[{ value: 'trondelag', label: 'Trøndelag' }]}
        />
        <FormField.FeedbackMessage>
          <FormField.FeedbackIcon />
          {'Region is required.'}
        </FormField.FeedbackMessage>
      </FormField.Root>
    </Flex>
  );
};
```

### Placeholder

You must provide `placeholder` text when the input does not have an initial value.

<Callout variant="tip">

Provide a default selected option whenever possible. This reduces the interaction cost by saving the user time and clicks.

</Callout>

```jsx
() => {
  const options = [
    { value: 'apple', label: 'Apple' },
    { value: 'orange', label: 'Orange' },
    { value: 'banana', label: 'Banana' }
  ];

  const [valueWithPlaceholder, setValueWithPlaceholder] = React.useState();
  const [value, setValue] = React.useState(options[0].value);

  return (
    <Flex flow="column">
      <FormField.Root as={Flex} flow="column">
        <FormField.Label>{'With placeholder'}</FormField.Label>
        <Select
          onChange={setValueWithPlaceholder}
          options={options}
          value={valueWithPlaceholder}
          placeholder="Please select a fruit"
        />
      </FormField.Root>
      <FormField.Root as={Flex} flow="column">
        <FormField.Label>{'No placeholder + initial value'}</FormField.Label>
        <Select onChange={setValue} options={options} value={value} />
      </FormField.Root>
    </Flex>
  );
};
```

### Disabled input

Pass `isDisabled` prop to the accompanying `FormField` and it will cascade down to the select input.

```jsx
<FormField.Root as={Flex} flow="column" isDisabled>
  <FormField.Label>{'Disabled select'}</FormField.Label>
  <Select
    onChange={() => {}}
    value="orange"
    options={[{ value: 'orange', label: 'Orange' }]}
  />
</FormField.Root>
```

You can also pass `isDisabled` prop directly to `Select`.

```jsx
<Select
  className="w100"
  aria-label="Select label"
  onChange={() => {}}
  isDisabled
  value="orange"
  options={[{ value: 'orange', label: 'Orange' }]}
/>
```

The component can show an option as disabled, by setting the `disabled` property on the option.

```jsx
() => {
  const options = [
    { value: 'apple', label: 'Apple' },
    { value: 'orange', label: 'Orange', disabled: true },
    { value: 'banana', label: 'Banana' }
  ];

  const [value, setValue] = React.useState(options[0].value);

  return (
    <FormField.Root as={Flex} flow="column">
      <FormField.Label>{'Disabled option'}</FormField.Label>
      <Select onChange={setValue} options={options} value={value} />
    </FormField.Root>
  );
};
```

### Sizes

Vera provides two `Select` sizes ‐ `medium` and `small`, with the `medium` size used by default. All sizes are aligned with sizes of other related components like [Button](/components/button) or [Text Input](/components/forms/text-input).

```jsx
() => {
  const options = [
    { value: 'apple', label: 'Apple' },
    { value: 'orange', label: 'Orange' },
    { value: 'banana', label: 'Banana' }
  ];

  const [value, setValue] = React.useState(options[0].value);

  return (
    <Flex flow="column">
      <Select
        size="small"
        onChange={setValue}
        options={options}
        value={value}
      />
      <Select
        size="medium"
        onChange={setValue}
        options={options}
        value={value}
      />
    </Flex>
  );
};
```

#### Size inheritance

`Select` automatically inherits size, when placed inside a [FormField component](/components/forms/form-field).

```jsx
() => {
  const options = [
    { value: 'apple', label: 'Apple' },
    { value: 'orange', label: 'Orange' },
    { value: 'banana', label: 'Banana' }
  ];

  const [value, setValue] = React.useState(options[0].value);

  return (
    <Flex flow="column">
      <FormField.Root as={Flex} flow="column" size="small">
        <FormField.Label>{'Small'}</FormField.Label>
        <Select onChange={setValue} options={options} value={value} />
      </FormField.Root>
      <FormField.Root as={Flex} flow="column">
        <FormField.Label>{'Medium'}</FormField.Label>
        <Select onChange={setValue} options={options} value={value} />
      </FormField.Root>
    </Flex>
  );
};
```

#### Responsive

`Select` supports responsive syntax for its `size` property, which means you can change its size based on the viewport.

```jsx
() => {
  const [value, setValue] = React.useState('');

  return (
    <Select
      size={{ '@initial': 'medium', '@mqLargeAndUp': 'small' }}
      value={value}
      onChange={setValue}
      aria-label="Input label"
      placeholder="Select option"
      options={[
        { value: 'option1', label: 'Option 1' },
        { value: 'option2', label: 'Option 2' },
        { value: 'option3', label: 'Option 3' }
      ]}
    />
  );
};
```

#### Multi-sizing

Vera provides `applySizes` utility, which lets you specify size "scopes" within your app.
All selects within a scope will share the same size unless overwritten on a per-control basis.

```jsx
() => {
  const [value, setValue] = React.useState('');
  const [value2, setValue2] = React.useState('');
  const options = [
    { value: 'option1', label: 'Option 1' },
    { value: 'option2', label: 'Option 2' },
    { value: 'option3', label: 'Option 3' }
  ];

  return (
    <Flex
      gap="spacingS"
      className={applySizes({
        control: 'small'
      })}
      flow="column"
    >
      <Select
        value={value}
        onChange={setValue}
        aria-label="Input label"
        placeholder="Select option"
        options={options}
      />
      <Select
        value={value2}
        onChange={setValue2}
        aria-label="Input label"
        placeholder="Select option"
        options={options}
      />
    </Flex>
  );
};
```

### Groups

Group related options together, uses the [optgroup](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup) element internally.

```jsx
<FormField.Root as={Flex} flow="column">
  <FormField.Label>{'Grouped cities'}</FormField.Label>
  <Select
    onChange={console.log}
    value="barcelona"
    options={[
      {
        label: 'Europe',
        options: [
          { value: 'stockholm', label: 'Stockholm' },
          { value: 'barcelona', label: 'Barcelona' },
          { value: 'athens', label: 'Athens' }
        ]
      },
      {
        label: 'Asia',
        options: [
          { value: 'bangkok', label: 'Bangkok' },
          { value: 'manila', label: 'Manila' },
          { value: 'jakarta', label: 'Jakarta' }
        ]
      }
    ]}
  />
</FormField.Root>
```

---

## API Reference

<Callout variant="tip">

In addition to the props below, you can pass all `React.SelectHTMLAttributes`.

</Callout>

| Name               | Type                                                                   | Default | Description                                                                                                                                                                                                                                  | Required |
| ------------------ | ---------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`              | `StitchesCss`                                                          |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants. |          |
| `selectCss`        | `StitchesCss`                                                          |         | Override the select input styles in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants.     |          |
| `isDisabled`       | `boolean`                                                              |         | When `true`, the input will be disabled, preventing the user from interacting with it.                                                                                                                                                       |          |
| `isReadOnly`       | `boolean`                                                              |         | When `true`, the input will be readonly, which means its value cannot be edited but it can still be selected and copied.                                                                                                                     |          |
| `isRequired`       | `boolean`                                                              |         | When `true`, the input will be required.                                                                                                                                                                                                     |          |
| `validationStatus` | `"error" \| "success" \| "warning"`                                    |         | Styles the input to match the status.                                                                                                                                                                                                        |          |
| `options`          | `(Option \| Group<Option>)[]`                                          |         | Array of options or groups of options to choose from.                                                                                                                                                                                        | Yes      |
| `value`            | `string \| number`                                                     |         | Value for the input.                                                                                                                                                                                                                         |          |
| `onChange`         | `(value: string, event: React.ChangeEvent<HTMLSelectElement>) => void` |         | Event handler called when an option is selected.                                                                                                                                                                                             | Yes      |
| `placeholder`      | `string`                                                               |         | Text to display as placeholder.                                                                                                                                                                                                              |          |
| `size`             | `"medium" \| "small"`                                                  |         | The size of the input.                                                                                                                                                                                                                       |          |
