# Select

**📖 Live documentation:** https://cds.coinbase.com/components/inputs/Select/

A Dropdown control for selecting from a list of options.

## Import

```tsx
import { Select } from '@coinbase/cds-web/controls/Select'
```

## Examples

### Default Composition

`Select` can take anything as a child, however, we strongly recommend that you use `SelectOption`. It has the same API as a `ListCell`, but with custom styles specific to usage within a `Select`. `SelectOption` also comes with a lot of baked in functionality, like keyboard navigation, accessibility properties, and focus behaviors.

```jsx live
function DefaultSelect() {
  const [value, setValue] = useState();
  const options = ['Option 1', 'Option 2', 'Option 3', 'Option 4', 'Option 5', 'Option 6'];
  return (
    <VStack padding={2}>
      <OldSelect value={value} placeholder="Choose something..." onChange={setValue}>
        {options.map((option) => (
          <SelectOption value={option} key={option} title={option} description="Description" />
        ))}
      </OldSelect>
    </VStack>
  );
}
```

### Value/Label Object Model

Sometimes you may want to surface a label instead of the select value. You can pass a `valueLabel` prop with the currently selected value's corresponding label, which will appear to be the value of the Select.

```jsx live
function DefaultSelect() {
  const [value, setValue] = useState();
  const options = [
    { value: '1', label: 'Option 1' },
    { value: '2', label: 'Option 2' },
    { value: '3', label: 'Option 3' },
    { value: '4', label: 'Option 4' },
  ];
  const selectedValueLabel = value && options.find((option) => option.value === value).label;
  return (
    <VStack padding={2}>
      <OldSelect
        value={value}
        valueLabel={selectedValueLabel}
        placeholder="Choose something..."
        onChange={setValue}
      >
        {options.map((option) => (
          <SelectOption
            value={option.value}
            key={option.value}
            title={option.label}
            description="Description"
          />
        ))}
      </OldSelect>
    </VStack>
  );
}
```

### Input Stack Options

The `Select` trigger can be customized similar to `TextInput`. These options are also available for mobile implementations.

#### Label and Helper Text

When space is tight, this brings the label inside of the Input. Should be used with a `compact` `SelectOption`.

```jsx live
function LabelHelperTextSelect() {
  const [value, setValue] = useState('Option 2');
  const options = ['Option 1', 'Option 2', 'Option 3', 'Option 4', 'Option 5', 'Option 6'];
  return (
    <VStack padding={2}>
      <OldSelect
        label="Make a selection"
        helperText="You can only choose one"
        value={value}
        onChange={setValue}
        startNode={<InputIcon name="calendar" />}
      >
        {options.map((option) => (
          <SelectOption value={option} key={option} title={option} description="Description" />
        ))}
      </OldSelect>
    </VStack>
  );
}
```

### Compact

When space is tight, this brings the label inside of the Input. Should be used with a `compact` `SelectOption`.

```jsx live
function CompactSelect() {
  const [value, setValue] = useState('Option 2');
  const options = ['Option 1', 'Option 2', 'Option 3', 'Option 4', 'Option 5', 'Option 6'];
  return (
    <VStack padding={2}>
      <OldSelect compact label="Make a selection" value={value} onChange={setValue}>
        {options.map((option) => (
          <SelectOption
            value={option}
            key={option}
            compact
            title={option}
            description="Description"
          />
        ))}
      </OldSelect>
    </VStack>
  );
}
```

### Variants

Variants can be used to surface positive or negative feedback.

```jsx live
function Variant() {
  const [value, setValue] = useState('Positive');
  const options = ['Positive', 'Negative', 'Primary', 'Secondary', 'Foreground'];
  return (
    <VStack padding={2}>
      <OldSelect
        variant={value.toLowerCase()}
        label="Make a selection"
        helperText="You can only choose one"
        value={value}
        onChange={setValue}
      >
        {options.map((option) => (
          <SelectOption value={option} key={option} title={option} />
        ))}
      </OldSelect>
    </VStack>
  );
}
```

### Label Variants

Select supports two label variants: `outside` (default) and `inside`. Note that the `compact` prop, when set to true, will override label variant preference.

:::warning

When using the `inside` label variant, you should always include a `placeholder` prop.

:::

```jsx live
<VStack gap={3}>
  <VStack>
    <Text as="p">
      <strong>Outside label (default):</strong>
    </Text>
    <OldSelect placeholder="Choose an option">
      <SelectOption value="option1" title="Option 1" description="Description" />
      <SelectOption value="option2" title="Option 2" description="Description" />
      <SelectOption value="option3" title="Option 3" description="Description" />
    </OldSelect>
  </VStack>

  <VStack>
    <Text as="p">
      <strong>Inside label:</strong>
    </Text>
    <OldSelect label="Choose Option" labelVariant="inside" placeholder="Select from list">
      <SelectOption value="option1" title="Option 1" description="Description" />
      <SelectOption value="option2" title="Option 2" description="Description" />
      <SelectOption value="option3" title="Option 3" description="Description" />
    </OldSelect>
  </VStack>

  <VStack>
    <Text as="p">
      <strong>Inside label (with start content):</strong>
    </Text>
    <OldSelect
      label="Filter Options"
      labelVariant="inside"
      startNode={<InputIcon name="search" />}
      placeholder="Search and select"
    >
      <SelectOption value="option1" title="Option 1" description="Description" />
      <SelectOption value="option2" title="Option 2" description="Description" />
      <SelectOption value="option3" title="Option 3" description="Description" />
    </OldSelect>
  </VStack>
</VStack>
```

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `name` | `string` | Yes | `-` | Field name of the multiple choice radio group. |
| `options` | `Record<RadioValue, ReactNode>` | Yes | `-` | Multiple choice options for the radio group. The object key represents the radio input value and the object value represents the radio option label. |
| `controlColor` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `bgPrimary` | Sets the checked/active color of each control in the group. |
| `direction` | `horizontal \| vertical` | No | `vertical` | Direction a group of components should flow. |
| `gap` | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1.5` | No | `-` | Gap to insert between siblings. |
| `label` | `null \| string \| number \| bigint \| false \| true \| ReactElement<unknown, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal \| Promise<AwaitedReactNode>` | No | `-` | Set a label summary for the group of radios. |
| `onChange` | `((value: RadioValue) => void)` | No | `-` | Handle change event when pressing on a radio option. |
| `ref` | `null \| (instance: HTMLInputElement \| null) => void \| (() => VoidOrUndefinedOnly) \| RefObject<HTMLInputElement \| null>` | No | `-` | - |
| `testID` | `string` | No | `-` | Used to locate this element in unit and end-to-end tests. Under the hood, testID translates to data-testid on Web. On Mobile, testID stays the same - testID |
| `value` | `string` | No | `-` | Currently selected value. |


