# Select

A Select is used to present a defined list of options to choose from.

## Design & usage guidelines

Nested within the Select component, Option defines the options that can be
selected. For grouping options with section headers, use Select.OptionGroup.

#### Custom grouped menu and browser support

V2 remains a native `<select>` by default. To enable the enhanced grouped menu
styling (bold section headers, edge‑to‑edge dividers and hover backgrounds), set
the `UNSAFE_experimentalStyles` prop on `Select`.

* When `UNSAFE_experimentalStyles` is true and the browser supports
  `appearance: base-select` (Chromium 123+), the select renders with the
  customizable grouped menu.
* In unsupported browsers, or when `UNSAFE_experimentalStyles` is not provided,
  the select remains native while still rendering the same `OptionGroup`
  structure.

#### Option Props

#### OptionGroup Props

## States

### Invalid

```tsx
import React from "react";
import { Option, Select } from "@jobber/components/Select";

export function SelectInvalidExample() {
  return (
    <Select invalid={true}>
      <Option value="sad">Tony</Option>
      <Option value="old">Steve</Option>
    </Select>
  );
}
```

### Disabled

```tsx
import React from "react";
import { Option, Select } from "@jobber/components/Select";

export function SelectDisabledExample() {
  return (
    <Select disabled={true}>
      <Option value="sad">Tony</Option>
      <Option value="old">Steve</Option>
    </Select>
  );
}
```

## Option Grouping

Use `Select.OptionGroup` to organize options with section headers for better
user experience and visual hierarchy. The `label` prop is required as it
provides the section header text.

### Basic Option Groups

```tsx
import React from "react";
import { Select } from "@jobber/components/Select";

export function SelectCustomOptionGroupsExample() {
  return (
    <Select
      placeholder="Select an option"
      version={2}
      UNSAFE_experimentalStyles={true}
    >
      <Select.OptionGroup label="Team A">
        <Select.Option value="alice">Alice</Select.Option>
        <Select.Option value="bob">Bob</Select.Option>
        <Select.Option value="charlie">Charlie</Select.Option>
      </Select.OptionGroup>
      <Select.OptionGroup label="Team B">
        <Select.Option value="diana">Diana</Select.Option>
        <Select.Option value="evan">Evan</Select.Option>
        <Select.Option value="frank">Frank</Select.Option>
      </Select.OptionGroup>
      <Select.OptionGroup label="Team C">
        <Select.Option value="grace">Grace</Select.Option>
        <Select.Option value="hector">Hector</Select.Option>
        <Select.Option value="isabel">Isabel</Select.Option>
      </Select.OptionGroup>
    </Select>
  );
}
```

### Disabled Option Groups

```tsx
import React from "react";
import { Select } from "@jobber/components/Select";

export function SelectCustomOptionGroupDisabledExample() {
  return (
    <Select
      version={2}
      UNSAFE_experimentalStyles
      placeholder="Select an option"
    >
      <Select.OptionGroup label="Available Items">
        <Select.Option value="option1">Option 1</Select.Option>
        <Select.Option value="option2">Option 2</Select.Option>
      </Select.OptionGroup>
      <Select.OptionGroup label="Unavailable Items" disabled>
        <Select.Option value="option3">Option 3</Select.Option>
        <Select.Option value="option4">Option 4</Select.Option>
      </Select.OptionGroup>
      <Select.OptionGroup label="More Items">
        <Select.Option value="option5">Option 5</Select.Option>
        <Select.Option value="option6">Option 6</Select.Option>
      </Select.OptionGroup>
    </Select>
  );
}
```


## Configuration

### Custom (Chromium) vs native

Select (V2) is native by default. Opt into the customizable Chrome UI with
`UNSAFE_experimentalStyles`. This enhances grouped menus in Chromium 123+ when
the browser supports `appearance: base-select`.

#### Alignment limitation (custom UI)

When using `UNSAFE_experimentalStyles`, the closed control (what you see as the
displayed value) is still rendered by the browser's picker. As a result,
right/center alignment of the displayed value is not configurable in Chromium's
customizable select.

* Need right/center alignment? Use the native Select (omit
  `UNSAFE_experimentalStyles`).
* You can still style the grouped dropdown (optgroup/option) in the custom UI,
  but the closed value alignment will remain default.

## Component customization

### Composable usage

Select supports composition via subcomponents:

* `Select.Option`: item in the list. Provide `value` and children as the label.
* `Select.OptionGroup`: group options under a `label`. Use with
  `UNSAFE_experimentalStyles` to opt into the customizable grouped menu in
  Chromium.

#### Customization links

* See
  ["A customizable select"](https://developer.chrome.com/blog/a-customizable-select)
  article for what the Chrome UI exposes: `::picker(select)`, option/optgroup
  styling, and transitions.

## UNSAFE\_ props (advanced usage)

General guidance on `UNSAFE_` props can be found in
[Customizing components](../customizing-components/customizing-components.md).

Select subcomponents allow `UNSAFE_className` and `UNSAFE_style` to target the
native elements:

* `Select.OptionGroup` maps to `<optgroup>`
* `Select.Option` maps to `<option>`

Note that native `<select>` UX differs per browser. Use `UNSAFE_` props with
caution and test across environments. In the custom UI (Chromium), only the
dropdown content is stylable; the closed value alignment is not.


## Props

### Web

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `align` | `"center" | "right"` | No | — | Determines the alignment of the text inside the input. |
| `autofocus` | `boolean` | No | — | Determines if the input should be auto-focused, using the HTML attribute |
| `children` | `ReactNode` | No | — | If you need to pass in a children. For example, `<options>` inside `<select>`. |
| `defaultValue` | `string | Date` | No | — | Initial value of the input. Only use this when you need to pre-populate the field with a data that is not controlled ... |
| `description` | `ReactNode` | No | — | Further description of the input, can be used for a hint. |
| `disabled` | `boolean` | No | — | Disable the input |
| `id` | `string` | No | — | A unique identifier for the input. |
| `inline` | `boolean` | No | — | Adjusts the form field to go inline with a content. This also silences the given `validations` prop. You'd have to us... |
| `inputRef` | `RefObject<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>` | No | — |  |
| `invalid` | `boolean` | No | — | Highlights the field red to indicate an error. |
| `maxLength` | `number` | No | — | Changes the width to roughly the same size as the maximum character length |
| `name` | `string` | No | — | Name of the input. |
| `onBlur` | `(event?: FocusEvent<Element, Element>) => void` | No | — | Blur callback. |
| `onChange` | `(newValue: string | number | boolean | Date, event?: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => void` | No | — | onChange handler that provides the new value (or event) @param newValue @param event |
| `onEnter` | `(event: KeyboardEvent<Element>) => void` | No | — | A callback to handle "Enter" keypress. This will only run if Enter is the only key. Will not run if Shift or Control ... |
| `onFocus` | `(event?: FocusEvent<Element, Element>) => void` | No | — | Focus callback. |
| `onValidation` | `(message: string) => void` | No | — | Callback to get the the status and message when validating a field @param message |
| `placeholder` | `string` | No | — | Text that appears inside the input when empty and floats above the value as a mini label once the user enters a value... |
| `prefix` | `Affix` | No | — | Adds a prefix label and icon to the field |
| `size` | `"small" | "large"` | No | — | Adjusts the interface to either have small or large spacing. |
| `suffix` | `{ onClick: () => void; readonly ariaLabel: string; readonly icon: IconNames; readonly label?: string; } | { onClick?: never; ariaLabel?: never; readonly label?: string; readonly icon?: IconNames; }` | No | — | Adds a suffix label and icon with an optional action to the field |
| `validations` | `RegisterOptions` | No | — | Show an error message above the field. This also highlights the the field red if an error message shows up. |
| `value` | `string | number | Date` | No | — | Set the component to the given value. |
| `version` | `1` | No | — | Experimental: Determine which version of the FormField to use. Right now this isn't used but it will be used in the f... |
| `wrapperRef` | `RefObject<HTMLDivElement>` | No | — |  |
