# Select

## Introduction

The Select component is a form input that allows users to choose one or multiple options from a predefined list. Built on Joy UI's Select, it provides a dropdown interface for selecting values within forms. Select is designed for data input scenarios where users need to pick from a set of options, making it ideal for forms, filters, and configuration settings.

```tsx
<Select options={options} />
```

| Field          | Description | Default |
| -------------- | ----------- | ------- |
| variant        | —           | —       |
| color          | —           | —       |
| size           | —           | —       |
| autoFocus      | —           | —       |
| placeholder    | —           | —       |
| startDecorator | —           | —       |
| endDecorator   | —           | —       |
| error          | —           | —       |
| helperText     | —           | —       |
| value          | —           | —       |
| defaultValue   | —           | —       |
| onChange       | —           | —       |
| options        | —           | options |

> ⚠️ **Don't Confuse Select with Dropdown** ⚠️
>
> - **Select**: For form value selection - the selected value becomes form data
> - **Dropdown**: For menus and action lists - triggers actions or navigation
>
> Choose the right component:
>
> - Less than 5 options → Consider RadioButton or RadioGroup
> - More than 20 options → Consider Autocomplete with search
> - Actions/navigation → Use Dropdown with Menu

> 💡 **Use built-in form props**
>
> This component natively supports form elements such as `label` and `helperText` props.
> When building forms, use these built-in props instead of manually composing labels and helper text with Typography.

## Usage

```tsx
import { Select } from '@ceed/cds';

const options = [
  { value: 'dog', label: 'Dog' },
  { value: 'cat', label: 'Cat' },
  { value: 'fish', label: 'Fish' },
];

function MyComponent() {
  return (
    <Select
      label="Choose a pet"
      options={options}
      defaultValue="dog"
    />
  );
}
```

## Examples

### Basic Select

The default Select with a list of options.

```tsx
<Select options={options} />
```

### Variants

Select supports different visual styles.

```tsx
<Stack spacing={4}>
  <Select defaultValue="dog" options={options} />
  <Select defaultValue="dog" variant="plain" options={options} />
  <Select defaultValue="dog" variant="soft" options={options} />
  <Select defaultValue="dog" variant="solid" options={options} />
</Stack>
```

### Sizes

Select comes in different sizes.

```tsx
<Stack spacing={4}>
  <Select defaultValue="dog" size="sm" options={options} />
  <Select defaultValue="dog" size="md" options={options} />
  <Select defaultValue="dog" size="lg" options={options} />
</Stack>
```

### Colors

Apply semantic colors to Select.

```tsx
<Stack spacing={4}>
  <Select defaultValue="dog" color="primary" options={options} />
  <Select defaultValue="dog" color="neutral" options={options} />
  <Select defaultValue="dog" color="success" options={options} />
  <Select defaultValue="dog" color="danger" options={options} />
  <Select defaultValue="dog" color="warning" options={options} />
</Stack>
```

### With Decorators

Add icons or badges to the Select.

```tsx
<Select placeholder="Select a pet…" startDecorator={<FavoriteBorder />} endDecorator={<Chip size="sm" color="danger" variant="soft">
  +5
</Chip>} sx={{
width: 240
}} options={options} />
```

### With Label

Select with an associated label.

```tsx
<>
  <Select label="Label" defaultValue="dog" options={options} />
</>
```

### With Helper Text

Add helper text for additional context.

```tsx
<>
  <Select label="Select" helperText="I'm helper text" defaultValue="dog" options={options} />
</>
```

### Error State

Show validation errors.

```tsx
<>
  <Select label="label" error defaultValue="dog" options={options} />
</>
```

### Form Control

Complete form integration with label and helper text.

```tsx
<>
  <Select label="Label" helperText="I'm helper text" defaultValue="dog" options={options} />
  <Select label="Label" helperText="I'm helper text" defaultValue="dog" error options={options} />
</>
```

### Required Field

Mark the Select as required.

```tsx
<Select
  options={options}
  label="Label"
  helperText="I'm helper text"
  required
/>
```

### Multiple Selection

Allow selecting multiple options.

```tsx
<Select
  options={options}
  label="Label"
  helperText="I'm helper text"
  defaultValue={['dog']}
  multiple
/>
```

### Controlled Select

Programmatically control the selected value.

```tsx
<div>
  <Select {...args} options={options} value={value} onChange={(event, newValue) => {
    setValue(newValue);
    args.onChange?.(event, newValue);
  }} />
  <Select {...args} options={['dog', 'cat', 'fish', 'bird'] as string[]} value={value} onChange={(event, newValue) => {
    setValue(newValue);
    args.onChange?.(event, newValue);
  }} />
  <Select {...args} options={['dog', 'cat', 'fish', 'bird'] as string[]} value={[value]} onChange={(event, newValue) => {
    setValue(newValue);
    args.onChange?.(event, newValue);
  }} multiple />
</div>
```

### Disabled Options

Individual options can be disabled.

```tsx
<Select
  options={options.map((option, idx) => ({
  ...option,
  disabled: idx % 2 === 0
}))}
  label="Disabled Options"
  defaultValue="dog"
/>
```

### Options with Secondary Text

Display additional information for each option.

```tsx
<Stack spacing={4} direction="row" alignItems="flex-start">
  {sizes.map(size => <Stack key={size} spacing={1}>
  <span style={{
    color: '#6366f1',
    fontSize: 12
  }}>{size}</span>
  <Select placeholder="Placeholder" options={optionsWithSecondaryText} sx={{
    minWidth: 200
  }} size={size} />
</Stack>)}
</Stack>
```

## When to Use

### ✅ Good Use Cases

- **Forms**: When users need to select a value that will be submitted as form data
- **Filters**: Selecting filter criteria for lists or search results
- **Settings**: Configuration options where user needs to pick one value
- **Data entry**: Standardized input where free text isn't appropriate
- **5-20 options**: Ideal number of choices for a Select
- **Single source of truth**: When the selected value should be clearly visible

### ❌ When Not to Use

- **Actions/navigation**: Use Dropdown with Menu instead
- **2-4 options visible at once**: Consider RadioGroup for better visibility
- **20+ options**: Use Autocomplete with search functionality
- **Complex selections**: Consider a different pattern if selections involve complex logic
- **Toggle between states**: Use Switch or Checkbox instead

## Common Use Cases

### Form with Select

```tsx
function UserForm() {
  const [country, setCountry] = useState('');
  const [role, setRole] = useState('');

  return (
    <form onSubmit={handleSubmit}>
      <Stack spacing={2}>
        <Select
          label="Country"
          required
          value={country}
          onChange={(e, val) => setCountry(val)}
          options={countries}
          placeholder="Select your country"
        />

        <Select
          label="Role"
          required
          value={role}
          onChange={(e, val) => setRole(val)}
          options={[
            { value: 'admin', label: 'Administrator' },
            { value: 'editor', label: 'Editor' },
            { value: 'viewer', label: 'Viewer' },
          ]}
        />

        <Button type="submit">Submit</Button>
      </Stack>
    </form>
  );
}
```

### Filter Select

```tsx
function ProductFilter({ onFilterChange }) {
  const [category, setCategory] = useState('all');
  const [sortBy, setSortBy] = useState('newest');

  useEffect(() => {
    onFilterChange({ category, sortBy });
  }, [category, sortBy]);

  return (
    <Stack direction="row" spacing={2}>
      <Select
        label="Category"
        size="sm"
        value={category}
        onChange={(e, val) => setCategory(val)}
        options={[
          { value: 'all', label: 'All Categories' },
          { value: 'electronics', label: 'Electronics' },
          { value: 'clothing', label: 'Clothing' },
          { value: 'home', label: 'Home & Garden' },
        ]}
      />

      <Select
        label="Sort By"
        size="sm"
        value={sortBy}
        onChange={(e, val) => setSortBy(val)}
        options={[
          { value: 'newest', label: 'Newest First' },
          { value: 'price-low', label: 'Price: Low to High' },
          { value: 'price-high', label: 'Price: High to Low' },
          { value: 'popular', label: 'Most Popular' },
        ]}
      />
    </Stack>
  );
}
```

### Multiple Select with Tags

```tsx
function TagSelect() {
  const [selectedTags, setSelectedTags] = useState([]);

  const tagOptions = [
    { value: 'urgent', label: 'Urgent' },
    { value: 'feature', label: 'Feature' },
    { value: 'bug', label: 'Bug' },
    { value: 'enhancement', label: 'Enhancement' },
    { value: 'documentation', label: 'Documentation' },
  ];

  return (
    <Select
      label="Tags"
      multiple
      value={selectedTags}
      onChange={(e, val) => setSelectedTags(val)}
      options={tagOptions}
      placeholder="Select tags..."
    />
  );
}
```

### Dependent Selects

```tsx
function LocationSelect() {
  const [country, setCountry] = useState('');
  const [city, setCity] = useState('');

  const cities = useMemo(() => {
    if (!country) return [];
    return getCitiesByCountry(country);
  }, [country]);

  return (
    <Stack spacing={2}>
      <Select
        label="Country"
        value={country}
        onChange={(e, val) => {
          setCountry(val);
          setCity(''); // Reset city when country changes
        }}
        options={countries}
      />

      <Select
        label="City"
        value={city}
        onChange={(e, val) => setCity(val)}
        options={cities}
        disabled={!country}
        placeholder={country ? 'Select city' : 'Select country first'}
      />
    </Stack>
  );
}
```

### With Custom Option Rendering

```tsx
function UserSelect() {
  const userOptions = [
    { value: 'user1', label: 'John Doe', secondaryText: 'john@example.com' },
    { value: 'user2', label: 'Jane Smith', secondaryText: 'jane@example.com' },
    { value: 'user3', label: 'Bob Johnson', secondaryText: 'bob@example.com' },
  ];

  return (
    <Select
      label="Assign to"
      options={userOptions}
      placeholder="Select a user..."
    />
  );
}
```

## Props and Customization

### Key Props

| Prop           | Type                                                           | Default      | Description                     |
| -------------- | -------------------------------------------------------------- | ------------ | ------------------------------- |
| `options`      | `Option[]`                                                     | `[]`         | Array of options to display     |
| `value`        | `T \| T[]`                                                     | -            | Selected value(s) (controlled)  |
| `defaultValue` | `T \| T[]`                                                     | -            | Default value (uncontrolled)    |
| `onChange`     | `function`                                                     | -            | Callback when selection changes |
| `multiple`     | `boolean`                                                      | `false`      | Allow multiple selections       |
| `label`        | `string`                                                       | -            | Label text above the Select     |
| `helperText`   | `string`                                                       | -            | Helper text below the Select    |
| `error`        | `boolean`                                                      | `false`      | Show error state                |
| `required`     | `boolean`                                                      | `false`      | Mark as required                |
| `disabled`     | `boolean`                                                      | `false`      | Disable the Select              |
| `placeholder`  | `string`                                                       | -            | Placeholder text                |
| `variant`      | `'plain' \| 'outlined' \| 'soft' \| 'solid'`                   | `'outlined'` | Visual style                    |
| `color`        | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'` | -            | Color scheme                    |
| `size`         | `'sm' \| 'md' \| 'lg'`                                         | `'md'`       | Component size                  |

### Option Type

```tsx
interface Option {
  value: string | number;
  label: string;
  secondaryText?: string;
  disabled?: boolean;
}
```

### Numeric Values

Select supports both string and numeric values:

```tsx
<Stack spacing={4}>
  <Select defaultValue={1} options={numericOptions} />
  <Select defaultValue={1} variant="plain" options={numericOptions} />
  <Select defaultValue={1} variant="soft" options={numericOptions} />
  <Select defaultValue={1} variant="solid" options={numericOptions} />
</Stack>
```

```tsx
const numericOptions = [
  { value: 1, label: 'Option 1' },
  { value: 2, label: 'Option 2' },
  { value: 3, label: 'Option 3' },
];

<Select options={numericOptions} defaultValue={1} />
```

### Custom Styling

```tsx
<Select
  options={options}
  sx={{
    minWidth: 200,
    '& .MuiSelect-button': {
      borderRadius: 'xl',
    },
  }}
/>
```

## Accessibility

Select components follow accessibility best practices:

### ARIA Attributes

- Uses native listbox role with proper ARIA attributes
- `aria-labelledby` connects to the label
- `aria-describedby` connects to helper text
- `aria-required` when required prop is true
- `aria-invalid` when error prop is true

### Keyboard Navigation

- **Tab**: Focus the Select
- **Enter/Space**: Open the dropdown
- **Arrow Up/Down**: Navigate through options
- **Home/End**: Jump to first/last option
- **Enter**: Select the focused option
- **Escape**: Close the dropdown

### Screen Reader Support

```tsx
<Select
  label="Country"
  helperText="Select your country of residence"
  options={countries}
  aria-label="Country selection"
/>
```

### Form Association

```tsx
<FormControl required error={hasError}>
  <FormLabel>Country</FormLabel>
  <Select options={countries} />
  <FormHelperText>{hasError ? 'Please select a country' : 'Required field'}</FormHelperText>
</FormControl>
```

## Best Practices

### ✅ Do

1. **Use clear labels**: Labels should clearly describe what the user is selecting

```tsx
// ✅ Good: Clear, specific label
<Select label="Preferred contact method" options={contactMethods} />

// ❌ Bad: Vague label
<Select label="Select" options={contactMethods} />
```

2. **Provide meaningful option labels**: Options should be easy to understand

```tsx
// ✅ Good: Descriptive options
{ value: 'express', label: 'Express Shipping (1-2 days)' }

// ❌ Bad: Cryptic options
{ value: 'exp', label: 'EXP' }
```

3. **Order options logically**: Alphabetically, by frequency, or by importance

4. **Include a placeholder**: Help users understand what to select

```tsx
<Select placeholder="Select a country..." options={countries} />
```

5. **Use helper text**: Provide additional context when needed

```tsx
<Select
  label="Timezone"
  helperText="Select the timezone for your reports"
  options={timezones}
/>
```

### ❌ Don't

1. **Don't use for actions**: Select is for data, not navigation or actions

```tsx
// ❌ Bad: Using Select for actions
<Select options={[
  { value: 'edit', label: 'Edit' },
  { value: 'delete', label: 'Delete' },
]} />

// ✅ Good: Use Dropdown for actions
<Dropdown>
  <MenuButton>Actions</MenuButton>
  <Menu>
    <MenuItem onClick={handleEdit}>Edit</MenuItem>
    <MenuItem onClick={handleDelete}>Delete</MenuItem>
  </Menu>
</Dropdown>
```

2. **Don't disable without explanation**: If options are unavailable, explain why

3. **Don't use with very few options**: Consider RadioGroup for 2-4 options

4. **Don't use with many options without search**: Use Autocomplete for 20+ options

## Performance Considerations

### Large Option Lists

For lists with many options, consider:

1. **Pagination or virtual scrolling**: For very large lists
2. **Autocomplete**: When users need to search through options
3. **Lazy loading**: Load options on demand

```tsx
// For many options, use Autocomplete instead
<Autocomplete
  options={largeOptionList}
  getOptionLabel={(option) => option.label}
  renderInput={(params) => <Input {...params} label="Search..." />}
/>
```

### Controlled vs Uncontrolled

Use controlled mode only when necessary:

```tsx
// Uncontrolled - simpler, better performance
<Select defaultValue="option1" options={options} />

// Controlled - when you need to sync with other state
const [value, setValue] = useState('option1');
<Select value={value} onChange={(e, val) => setValue(val)} options={options} />
```

### Memoize Options

When options are computed, memoize them:

```tsx
const options = useMemo(() =>
  data.map(item => ({
    value: item.id,
    label: item.name,
  })),
[data]);

<Select options={options} />
```

Select is a fundamental form component that provides a clean interface for choosing from predefined options. Use it appropriately to create intuitive forms and ensure users can easily make selections.
