# Select

A control for selecting from a list of options.

## Import

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

## Examples

### Default Composition

The mobile version of `Select` is quite different from web; where on mobile, `Select` is just the trigger to toggle the visibility of a `Menu` that is contained in a `Tray`.

On mobile, all `SelectOption`s must be wrapped in a `Menu`. Think of it as a controlled `Select` on web, where you pass it the `value` and `onChange` handler.

```jsx
const SelectMobile = () => {
  const [isTrayVisible, { toggleOff: handleClose, toggleOn: handleOpenTray }] = useToggler(false);
  const [value, setValue] = useState();
  const trayRef = useRef(undefined);

  const options = ['Option 1', 'Option 2', 'Option 3', 'Option 4', 'Option 5'];

  const handleOptionPress = () => {
    trayRef.current?.handleClose();
  };

  return (
    <>
      <OldSelect value={value} onPress={handleOpenTray} />
      {isTrayVisible && (
        <Tray title={title} onCloseComplete={handleClose} ref={trayRef}>
          {/* You must wrap options in Menu. Treat it as a Select on web */}
          <Menu value={value} onChange={setValue}>
            {options.map((option: string) => (
              <SelectOption
                key={option}
                title={option}
                description="BTC"
                onPress={handleOptionPress}
                value={option}
              />
            ))}
          </Menu>
        </Tray>
      )}
    </>
  );
};
```

### 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
const SelectWithValueLabel = () => {
  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 (
    <>
      <OldSelect
        value={value}
        valueLabel={selectedValueLabel}
        placeholder="Choose something..."
        onPress={handleOpenTray}
      />
      {isTrayVisible && (
        <Tray title="Select Option" onCloseComplete={handleClose} ref={trayRef}>
          <Menu value={value} onChange={setValue}>
            {options.map((option) => (
              <SelectOption
                key={option.value}
                title={option.label}
                description="Description"
                onPress={handleOptionPress}
                value={option.value}
              />
            ))}
          </Menu>
        </Tray>
      )}
    </>
  );
};
```

### Input Stack Options

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

#### Label and Helper Text

You can add a label above the input and helper text below to provide context and guidance to users.

```jsx
<OldSelect
  label="Make a selection"
  helperText="You can only choose one"
  value={value}
  onChange={setValue}
  startNode={<InputIcon name="calendar" />}
>
  ...
</OldSelect>
```

### Compact

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

```jsx
<OldSelect compact label="Make a selection" value={value} onChange={setValue}>
  ...
</OldSelect>
```

### Variants

Variants can be used to surface positive or negative feedback. The available variants are `positive`, `negative`, `primary`, `foreground`, `foregroundMuted`, and `secondary`.

```jsx
<OldSelect variant="positive" label="Make a selection">
  ...
</OldSelect>
```

### 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.

:::

#### Outside label (default)

```jsx
<OldSelect label="Choose Option" placeholder="Select from list">
  ...
</OldSelect>
```

#### Inside label

```jsx
<OldSelect label="Choose Option" labelVariant="inside" placeholder="Select from list">
  ...
</OldSelect>
```

#### Inside label (with start content)

```jsx
<OldSelect
  label="Filter Options"
  labelVariant="inside"
  startNode={<InputIcon name="search" />}
  placeholder="Search and select"
>
  ...
</OldSelect>
```

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `options` | `Record<T, 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 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | Gap to insert between siblings. |
| `label` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Set a label summary for the group of radios. |
| `onChange` | `((value: T, checked?: boolean \| undefined) => void) \| undefined` | No | `-` | Handle change event when pressing on a radio option. |
| `radioAccessibilityLabel` | `string` | No | `-` | A11Y label to indicate order of radio buttons when focused on one button |
| `ref` | `null \| (instance: View \| null) => void \| RefObject<View>` | 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. |


