import { FormExamples, MDXLayoutNext } from '@/components';

export const meta = {
  templateTitle: 'Select',
  description: 'Form component | Fluid Design',
  date: '2023-02-01',
  author: 'Oliver Pan',
  tags: [
    'fluid ui',
    'react',
    'framer motion',
    'headless ui',
    'tailwindcss',
    'form',
    'select',
  ],
};

export default (props) => (
  <MDXLayoutNext meta={meta} components={FormExamples} {...props} />
);

# Select

Select are used to select a single value from a list of options.
It supports single select and multiple select. It also supports
object as data source. Below is a complete example of a select component.

<CodeFrame title=''>
  <Select.Demo />
</CodeFrame>

<CH.Code style={{height:"36rem"}}>

```jsx main.jsx
import { Form, Select, SubmitButton } from '@fluid-design/fluid-ui';
import { ShoppingCartIcon, XMarkIcon } from '@heroicons/react/24/outline';
import { useState } from 'react';
import * as Yup from 'yup';

function Example() {
  const [isSubmitted, setIsSubmitted] = useState(false);
  const validationSchema = Yup.object().shape({
    state: Yup.object().required('State is required'),
    reservationTime: Yup.string().required('Reservation time is required'),
    food: Yup.array().min(1, 'You must select at least one food'),
  });
  return (
    <Form
      onSubmit={(values, { setSubmitting }) => {
        setTimeout(() => {
          setSubmitting(false);
          setIsSubmitted(true);
          setTimeout(() => {
            setIsSubmitted(false);
          }, 2000);
        }, 2000);
      }}
      initialValues={{
        state: states[3],
        reservationTime: '',
        food: [],
      }}
      validationSchema={validationSchema}
    >
      <Select itemKey='name' list={states} name='state' autoComplete='state' />
      <Select
        name='reservationTime'
        label='Reservation Time'
        placeholder='Select a time'
        list={reservationTime}
        hasEmptyOption
        emptyOptionText='Unspecified'
      />
      <Select
        name='food'
        itemKey='name'
        disabledKey='unavailable'
        list={food}
        label="What's on the menu? (max 4 items)"
        placeholder='Select your favorites'
        multiple={4}
      />
      <SubmitButton
        className='w-full btn-light-primary dark:btn-bold-primary'
        label='Order'
        isLoaded={isSubmitted}
        iconStart={ShoppingCartIcon}
        loadedOptions={{
          text: 'Order submitted!',
        }}
      />
    </Form>
  );
}
```

```ts food.ts
export const food = [
  {
    id: 1,
    name: 'Pizza',
    calories: 300,
    unavailable: false,
  },
  {
    id: 2,
    name: 'Burger',
    calories: 400,
    unavailable: false,
  },
  {
    id: 3,
    name: 'Coke',
    calories: 150,
    unavailable: false,
  },
  {
    id: 4,
    name: 'Fries',
    calories: 250,
    unavailable: false,
  },
  {
    id: 5,
    name: 'Hot Dog (Sold Out)',
    calories: 550,
    unavailable: true,
  },
  {
    id: 6,
    name: 'Taco',
    calories: 450,
    unavailable: false,
  },
  {
    id: 7,
    name: 'Sandwich (Sold Out)',
    calories: 600,
    unavailable: true,
  },
  {
    id: 8,
    name: 'Ice Cream',
    calories: 500,
    unavailable: false,
  },
  {
    id: 9,
    name: 'Donut (Sold Out)',
    calories: 650,
    unavailable: true,
  },
  {
    id: 10,
    name: 'Sushi',
    calories: 700,
    unavailable: false,
  },
  {
    id: 11,
    name: 'Salad',
    calories: 200,
    unavailable: false,
  },
  {
    id: 12,
    name: 'Coffee',
    calories: 100,
    unavailable: false,
  },
];
```

```ts reservation-time.ts
export const reservationTime = [
  '1 AM',
  '2 AM',
  '3 AM',
  '4 AM',
  '5 AM',
  '6 AM',
  '7 AM',
  '8 AM',
  '9 AM',
  '10 AM',
  '11 AM',
  '12 PM',
  '1 PM',
  '2 PM',
  '3 PM',
  '4 PM',
  '5 PM',
  '6 PM',
  '7 PM',
  '8 PM',
  '9 PM',
  '10 PM',
  '11 PM',
  '12 AM',
];
```

```ts states.ts
export const states = [
  { id: 'AL', name: 'Alabama' },
  { id: 'AK', name: 'Alaska' },
  { id: 'AZ', name: 'Arizona' },
  { id: 'AR', name: 'Arkansas' },
  { id: 'CA', name: 'California' },
  { id: 'CO', name: 'Colorado' },
  { id: 'CT', name: 'Connecticut' },
  { id: 'DE', name: 'Delaware' },
  { id: 'DC', name: 'District Of Columbia' },
  { id: 'FL', name: 'Florida' },
  { id: 'GA', name: 'Georgia' },
  { id: 'HI', name: 'Hawaii' },
  { id: 'ID', name: 'Idaho' },
  { id: 'IL', name: 'Illinois' },
  { id: 'IN', name: 'Indiana' },
  { id: 'IA', name: 'Iowa' },
  { id: 'KS', name: 'Kansas' },
  { id: 'KY', name: 'Kentucky' },
  { id: 'LA', name: 'Louisiana' },
  { id: 'ME', name: 'Maine' },
  { id: 'MD', name: 'Maryland' },
  { id: 'MA', name: 'Massachusetts' },
  { id: 'MI', name: 'Michigan' },
  { id: 'MN', name: 'Minnesota' },
  { id: 'MS', name: 'Mississippi' },
  { id: 'MO', name: 'Missouri' },
  { id: 'MT', name: 'Montana' },
  { id: 'NE', name: 'Nebraska' },
  { id: 'NV', name: 'Nevada' },
  { id: 'NH', name: 'New Hampshire' },
  { id: 'NJ', name: 'New Jersey' },
  { id: 'NM', name: 'New Mexico' },
  { id: 'NY', name: 'New York' },
  { id: 'NC', name: 'North Carolina' },
  { id: 'ND', name: 'North Dakota' },
  { id: 'OH', name: 'Ohio' },
  { id: 'OK', name: 'Oklahoma' },
  { id: 'OR', name: 'Oregon' },
  { id: 'PA', name: 'Pennsylvania' },
  { id: 'RI', name: 'Rhode Island' },
  { id: 'SC', name: 'South Carolina' },
  { id: 'SD', name: 'South Dakota' },
  { id: 'TN', name: 'Tennessee' },
  { id: 'TX', name: 'Texas' },
  { id: 'UT', name: 'Utah' },
  { id: 'VT', name: 'Vermont' },
  { id: 'VA', name: 'Virginia' },
  { id: 'WA', name: 'Washington' },
  { id: 'WV', name: 'West Virginia' },
  { id: 'WI', name: 'Wisconsin' },
  { id: 'WY', name: 'Wyoming' },
];
```

</CH.Code>

## Basic example

<CodeFrame title='Basic example'>
  <Select.Basic />
</CodeFrame>

```jsx
import { Form, Select } from '@fluid-design/fluid-ui';

function Example() {
  const cars = [
    'Audi',
    'BMW',
    'Chevrolet',
    'Dodge',
    'Ford',
    'Honda',
    'Toyota',
    'Tesla',
    'Volkswagen',
  ];
  return (
    <Form
      onSubmit={() => null}
      initialValues={{
        car: '',
      }}
    >
      <Select name='car' list={cars} label='Select a car' />
    </Form>
  );
}
```

## Multiple select

To allow multiple selections, pass `multiple` prop, and pass an array of values to `value` prop.
If you want to set a maximum number of selections, you can do so by setting `multiple` prop to a number.

```jsx
import { Form, Select } from '@fluid-design/fluid-ui';

function Example() {
  const cars = [
    'Audi',
    'BMW',
    'Chevrolet',
    'Dodge',
    'Ford',
    'Honda',
    'Toyota',
    'Tesla',
    'Volkswagen',
  ];
  return (
    <Form
      onSubmit={() => null}
      initialValues={{
        cars: [],
      }}
    >
      <Select name='cars' list={cars} label='Select cars' multiple />
    </Form>
  );
}
```

## Empty option

If you want to have an empty option, you can add `hasEmptyOption` prop.
You can also customize the empty option by passing a string to `emptyOptionText` prop.

```jsx
<Select
  name='car'
  list={cars}
  label='Select a car'
  // mark
  hasEmptyOption
  // mark
  emptyOptionText="I don't have a car"
/>
```

## Custom Components

You can replace `Option` and `SelectedOption` components with your own.

<CodeFrame title='Custom Components'>
  <Select.CustomSelect />
</CodeFrame>

```jsx
import { Form, Select, SubmitButton } from '@fluid-design/fluid-ui';

function Example() {
  return (
    <Form
      onSubmit={() => null}
      initialValues={{
        food: [],
      }}
    >
      <Select
        name='food'
        list={food}
        itemKey='name'
        label="What's on the menu?"
        placeholder='Select as many as you like'
        multiple
        itemClassName='flex flex-wrap'
        rednerOptionItem={({ item, Option }) => (
          <Option
            value={item.name}
            className={({ active, selected, disabled }) =>
              clsxm(
                'flex flex-row items-center justify-start gap-2 px-2 py-1',
                'bg-white',
                active && 'bg-gray-100',
                selected && 'bg-blue-200',
                disabled && 'bg-gray-200'
              )
            }
            disabled={item.available === false}
          >
            {({ active, selected, disabled }) => (
              <>
                <div className='h-4 w-4'>
                  {selected && '✓'}
                  {disabled && '🚫'}
                </div>
                <div className='flex-grow'>{item.name}</div>
              </>
            )}
          </Option>
        )}
        renderSelectedItem={({ item, remove }) => (
          <button
            onClick={remove}
            className='flex flex-row items-center justify-start gap-2 rounded-full bg-primary-200 px-2 py-1'
          >
            <div className='flex-grow text-sm'>{item.name}</div>
            <XMarkIcon className='h-4 w-4' />
          </button>
        )}
      />
    </Form>
  );
}
```

## Component API

| Prop                     | Default | Description                                                                                                                       |
| ------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `name`                   |         | `String` <Table.D> Name of the field. </Table.D>                                                                                  |
| `list`                   |         | `Array` <Table.D> List of options. </Table.D>                                                                                     |
| `listClassName`          |         | `String` <Table.D> Class name of the list. </Table.D>                                                                             |
| `buttonClassName`        |         | `String` <Table.D> Class name of the button. </Table.D>                                                                           |
| `labelClassName`         |         | `String` <Table.D> Class name of the label. </Table.D>                                                                            |
| `itemClassName`          |         | `String` <Table.D> Class name of the input item. </Table.D>                                                                       |
| `selectedItemsClassName` |         | `String` <Table.D> Class name of the selected items container. </Table.D>                                                         |
| `className`              |         | `String` <Table.D> Class name of the select. </Table.D>                                                                           |
| `placeholder`            |         | `String` <Table.D> Placeholder of the select. </Table.D>                                                                          |
| `description`            |         | `String` <Table.D> Description of the select. </Table.D>                                                                          |
| `disabled`               | `false` | `Boolean` <Table.D> If `true`, disables the select. </Table.D>                                                                    |
| `disabledKey`            |         | `String` <Table.D> Key of the item in the list that should be disabled. </Table.D>                                                |
| `itemKey`                |         | `String` <Table.D> Key of the item in the list. </Table.D>                                                                        |
| `multiple`               | `false` | `Boolean \| Number` <Table.D> If `true`, allows multiple selections. If a number, sets a maximum number of selections. </Table.D> |
| `label`                  |         | `String` <Table.D> Label of the select. </Table.D>                                                                                |
| `hasEmptyOption`         | `false` | `Boolean` <Table.D> If `true`, adds an empty option. </Table.D>                                                                   |
| `emptyOptionText`        | `''`    | `String` <Table.D> Text of the empty option. </Table.D>                                                                           |
