# Dropdown

A dropdown lets people choose one or more options from a list. It can be used in forms where the options require custom styling \[or as a component to filter or sort information].

## Best practices

### Do

- Use placeholder text as an extra hint about the available options.
- Use the text prop to define a string value for complex options, especially options containing JSX.
- Set inlinePopup when possible for better VoiceOver support.

### Don't

- Use placeholder text as the dropdown label.
- Repeat the same word or phrase at the beginning of every option.

## Behavior and states

- If placeholder text is not set, dropdowns show as empty until a selection is made.
- Selecting a closed single-select field opens the list of options. Choosing an option closes the field.
- For multi-select interactions, each list item is accompanied by a checkbox.
- A multi-select list stays open until someone dismisses it by clicking off the list or pressing Esc.
- Put Dropdown in a Field if you need a label, info button, and validation.

## Default

Source: CoreAI.

[Download source](/coreai-design-system/source/examples/components-dropdown--default.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { useId } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import * as React from 'react';

export const Default = () => {
    const dropdownId = useId('dropdown-default');
    const options = [
        'Cat',
        'Caterpillar',
        'Corgi',
        'Chupacabra',
        'Dog',
        'Ferret',
        'Fish',
        'Fox',
        'Hamster',
        'Snake',
    ];
    const styles = /* css */ `
      .dropdown-default-example {
        display: grid;
        grid-template-rows: repeat(1fr);
        justify-items: start;
        gap: var(--spacingVerticalXXS);
        max-width: 400px;
      }
    `;
    return (<>
        <style>{styles}</style>
        <div className="dropdown-default-example">
          <label htmlFor={dropdownId}>Best pet</label>
          <Dropdown id={dropdownId} placeholder="Select an animal">
            {options.map((option) => (<Option key={option} disabled={option === 'Ferret'}>
                {option}
              </Option>))}
          </Dropdown>
        </div>
      </>);
};

export default Default;
```

## API

Generated CoreAI prop summaries, not replacement type declarations. Most native DOM/event and ARIA props are omitted. `?` means optional; JSDoc shows defaults, deprecations, and conditional requirements. Defaults assume the standard CoreAI provider.

### Dropdown API

A Dropdown component that extends Fluent UI's Dropdown.

```ts
interface DropdownProps {
  /**
   * Controls the colors and borders of the combobox trigger.
   * @default 'outline'
   */
  appearance?: "outline" | "filled-darker" | "filled-lighter" | "underline";

  as?: "button";

  /**
   * The primary slot, the element with role="combobox"
   */
  button?: NonNullable<WithSlotShorthandValue<{ as?: "button"; } & Omit<Omit<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & { ref?: ((instance: HTMLButtonElement | null) => void) | RefObject<HTMLButtonElement> | null; }, "children"> & { children?: any; }> | null> | undefined;

  children?: any;

  className?: string;

  /**
   * If set, the combobox will show an icon to clear the current value.
   */
  clearable?: boolean;

  /**
   * The dropdown clear icon
   */
  clearButton?: WithSlotShorthandValue<{ as?: "button"; } & Omit<Omit<DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & { ref?: ((instance: HTMLButtonElement | null) => void) | RefObject<HTMLButtonElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  /**
   * The default open state when open is uncontrolled
   */
  defaultOpen?: boolean;

  /**
   * For an uncontrolled component, sets the initial selection.
   * If this is set, the `defaultValue` prop MUST also be set.
   */
  defaultSelectedOptions?: string[];

  /**
   * The default value displayed in the trigger input or button when the combobox's value is uncontrolled
   */
  defaultValue?: string | (readonly string[] & string);

  /**
   * Disable auto-focusing on the first item when mounting.
   * @default false
   */
  disableAutoFocus?: boolean;

  /**
   * Collapse the control to its content width when nothing is selected and
   * grow it with the typed/selected content. Only available when `label` is set.
   */
  dynamicWidth?: boolean;

  /**
   * The dropdown arrow icon
   */
  expandIcon?: WithSlotShorthandValue<{ as?: "span"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & { ref?: ((instance: HTMLSpanElement | null) => void) | RefObject<HTMLSpanElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  /**
   * Render the combobox's popup inline in the DOM.
   * This has accessibility benefits, particularly for touch screen readers.
   */
  inlinePopup?: boolean;

  /**
   * Optional inline label rendered inside the control, before the value.
   */
  label?: string;

  /**
   * The dropdown listbox slot
   */
  listbox?: WithSlotShorthandValue<Omit<ListboxSlots, "root"> & Omit<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }, "ref"> & SelectionProps & { disableAutoFocus?: boolean | undefined; } & RefAttributes<HTMLDivElement>> | null | undefined;

  /**
   * Where the portal children are mounted on DOM
   * @default a new element on document.body without any styling
   */
  mountNode?: HTMLElement | { element?: HTMLElement | null; className?: string; } | null | undefined;

  /**
   * Sets the selection type to multiselect.
   * Set this to true for multiselect, even if fully controlling selection state.
   * This enables styles and accessibility properties to be set.
   * @default false
   */
  multiselect?: boolean;

  onActiveOptionChange?: EventHandler<ActiveOptionChangeData>;

  /**
   * Callback when the open/closed state of the dropdown changes
   */
  onOpenChange?: ((e: ComboboxBaseOpenEvents, data: ComboboxBaseOpenChangeData) => void);

  /**
   * Callback when an option is selected
   */
  onOptionSelect?: ((event: SelectionEvents, data: OptionOnSelectData) => void);

  /**
   * Sets the open/closed state of the dropdown.
   * Use together with onOpenChange to fully control the dropdown's visibility
   */
  open?: boolean;

  /**
   * If set, the placeholder will show when no value is selected
   */
  placeholder?: string;

  /**
   * Configure the positioning of the combobox dropdown.
   * Please refer to the [positioning documentation](https://react.fluentui.dev/?path=/docs/concepts-developer-positioning-components--default#anchor-to-target)
   * for more details.
   */
  positioning?: PositioningShorthand;

  ref?: Ref<HTMLButtonElement>;

  /**
   * The root dropdown slot
   */
  root?: NonNullable<WithSlotShorthandValue<{ as?: "div"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null; }, "children"> & { children?: any; }> | null> | undefined;

  /**
   * An array of selected option keys.
   * Use this with `onOptionSelect` to directly control the selected option(s)
   * If this is set, the `value` prop MUST also be controlled.
   */
  selectedOptions?: string[];

  /**
   * Controls the size of the combobox faceplate
   * @default 'medium'
   */
  size?: "small" | "medium" | "large";

  style?: CSSProperties;

  /**
   * Controls text overflow behavior for the value. When true, long text is truncated with an ellipsis.
   */
  truncateTextOverflow?: boolean;

  /**
   * The value displayed by the Combobox.
   * Use this with `onOptionSelect` to directly control the displayed value string
   */
  value?: string | (readonly string[] & string);
}
```

### Listbox API

Listbox component: a standalone selection control, or the popup in a Combobox

```ts
interface ListboxProps {
  as?: "div";

  children?: any;

  className?: string;

  /**
   * For an uncontrolled component, sets the initial selection.
   * If this is set, the `defaultValue` prop MUST also be set.
   */
  defaultSelectedOptions?: string[];

  /**
   * Disable auto-focusing on the first item when mounting.
   * @default false
   */
  disableAutoFocus?: boolean;

  /**
   * Sets the selection type to multiselect.
   * Set this to true for multiselect, even if fully controlling selection state.
   * This enables styles and accessibility properties to be set.
   * @default false
   */
  multiselect?: boolean;

  /**
   * Callback when an option is selected
   */
  onOptionSelect?: ((event: SelectionEvents, data: OptionOnSelectData) => void);

  ref?: Ref<HTMLDivElement>;

  /**
   * An array of selected option keys.
   * Use this with `onOptionSelect` to directly control the selected option(s)
   * If this is set, the `value` prop MUST also be controlled.
   */
  selectedOptions?: string[];

  style?: CSSProperties;
}
```

### Option API

Option component: a styled child option of a Combobox

```ts
interface OptionProps {
  as?: "div";

  /**
   * The check icon that is visible for selected options
   */
  checkIcon?: WithSlotShorthandValue<{ as?: "span"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & { ref?: ((instance: HTMLSpanElement | null) => void) | RefObject<HTMLSpanElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  children?: any;

  className?: string;

  /**
   * Sets an option to the `disabled` state.
   * Disabled options cannot be selected, but are still keyboard navigable
   */
  disabled?: boolean;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;

  /**
   * An optional override the string value of the Option's display text,
   * defaulting to the Option's child content.
   * This is used as the Dropdown button's or Combobox input's value when the option is selected,
   * and as the comparison for type-to-find keyboard functionality.
   * The string value of the Option's display text when the Option's children are not a string.
   * This is used as the Dropdown button's or Combobox input's value when the option is selected,
   * and as the comparison for type-to-find keyboard functionality.
   */
  text?: string;

  /**
   * Defines a unique identifier for the option.
   * Use this to control selectedOptions, or to get the option value in the onOptionSelect callback.
   * Defaults to `text` if not provided.
   */
  value?: string;
}
```

## Implementation

CoreAI 0.12.0; Fluent 9.74.9.

[Setup and dependencies](/coreai-design-system/guides/Package.md).

Import components from `@coreai-ds/react-components`. CoreAI guidance above takes precedence over API demonstration examples.

## Active Option Change

Source: Fluent, adapted for CoreAI.

OnActiveOptionChange notifies the user when the active option in the Dropdown was changed by keyboard. To react on mouse hover events, use onMouseEnter on the invididual options.

[Download source](/coreai-design-system/source/examples/components-dropdown--active-option-change.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import * as React from 'react';
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import { Persona } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '2px',
        maxWidth: '400px',
    },
});

export const ActiveOptionChange = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const dropdownId = useId('dropdown');
    const styles = useStyles();
    const [activeOptionText, setActiveOptionText] = React.useState('');
    const onActiveOptionChange = React.useCallback<NonNullable<DropdownProps['onActiveOptionChange']>>((_, data) => {
        if (data?.nextOption?.text) {
            setActiveOptionText(data?.nextOption?.text);
        }
    }, [setActiveOptionText]);
    const onMouseEnter = React.useCallback((e: React.MouseEvent<HTMLDivElement>) => {
        setActiveOptionText(`${e.currentTarget.textContent} (Mouse enter)`);
    }, [setActiveOptionText]);
    return (<div className={styles.root}>
      {activeOptionText}
      <label htmlFor={dropdownId}>Schedule a meeting</label>
      <Dropdown id={dropdownId} onActiveOptionChange={onActiveOptionChange} {...props}>
        <Option text="Katri Athokas" onMouseEnter={onMouseEnter}>
          <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Katri Athokas" presence={{
            status: 'available',
        }} secondaryText="Available"/>
        </Option>
        <Option text="Elvia Atkins" onMouseEnter={onMouseEnter}>
          <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Elvia Atkins" presence={{
            status: 'busy',
        }} secondaryText="Busy"/>
        </Option>
        <Option text="Cameron Evans" onMouseEnter={onMouseEnter}>
          <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Cameron Evans" presence={{
            status: 'away',
        }} secondaryText="Away"/>
        </Option>
        <Option text="Wanda Howard" onMouseEnter={onMouseEnter}>
          <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Wanda Howard" presence={{
            status: 'out-of-office',
        }} secondaryText="Out of office"/>
        </Option>
      </Dropdown>
    </div>);
};

export default ActiveOptionChange;
```

## Appearance

Source: Fluent, adapted for CoreAI.

A Dropdown can have the following `appearance` variants:
- `outline` (default): has a border around all four sides.
- `underline`: only has a bottom border.
- `filled-darker`: no border, only a subtle background color difference against a white page.
- `filled-lighter`: no border, and a white background.

[Download source](/coreai-design-system/source/examples/components-dropdown--appearance.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '20px',
        maxWidth: '400px',
        '> div': {
            display: 'grid',
            gridTemplateRows: 'repeat(1fr)',
            justifyItems: 'start',
            gap: '2px',
            // need padding to see the background color for filled variants
            padding: '5px 20px 10px',
        },
    },
    // filledLighter and filledDarker appearances depend on particular background colors
    filledLighter: {
        backgroundColor: tokens.colorNeutralBackgroundInverted,
        '> label': {
            color: tokens.colorNeutralForegroundInverted2,
        },
        '> h3': {
            color: tokens.colorNeutralForegroundInverted2,
        },
    },
    filledDarker: {
        backgroundColor: tokens.colorNeutralBackgroundInverted,
        '> label': {
            color: tokens.colorNeutralForegroundInverted2,
        },
        '> h3': {
            color: tokens.colorNeutralForegroundInverted2,
        },
    },
});

export const Appearance = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const dropdownId = useId('dropdown');
    const styles = useStyles();
    return (<div className={styles.root}>
      <div>
        <h3>Outline</h3>
        <label htmlFor={`${dropdownId}-outline`}>Select an animal</label>
        <Dropdown id={`${dropdownId}-outline`} placeholder="-" appearance="outline" {...props}>
          <Option>Cat</Option>
          <Option>Dog</Option>
          <Option>Bird</Option>
        </Dropdown>
      </div>

      <div>
        <h3>Underline</h3>
        <label htmlFor={`${dropdownId}-underline`}>Select an animal</label>
        <Dropdown id={`${dropdownId}-underline`} placeholder="-" appearance="underline" {...props}>
          <Option>Cat</Option>
          <Option>Dog</Option>
          <Option>Bird</Option>
        </Dropdown>
      </div>

      <div className={styles.filledDarker}>
        <h3>Filled Darker</h3>
        <label htmlFor={`${dropdownId}-filledDarker`}>Select an animal</label>
        <Dropdown id={`${dropdownId}-filledDarker`} placeholder="-" appearance="filled-darker" {...props}>
          <Option>Cat</Option>
          <Option>Dog</Option>
          <Option>Bird</Option>
        </Dropdown>
      </div>

      <div className={styles.filledLighter}>
        <h3>Filled Lighter</h3>
        <label htmlFor={`${dropdownId}-filledLighter`}>Select an animal</label>
        <Dropdown id={`${dropdownId}-filledLighter`} placeholder="-" appearance="filled-lighter" {...props}>
          <Option>Cat</Option>
          <Option>Dog</Option>
          <Option>Bird</Option>
        </Dropdown>
      </div>
    </div>);
};

export default Appearance;
```

## Clearable

Source: Fluent, adapted for CoreAI.

A Dropdown can be clearable and let users remove their selection. Note: this is not supported in multiselect mode yet.

[Download source](/coreai-design-system/source/examples/components-dropdown--clearable.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Label } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '2px',
        maxWidth: '400px',
    },
});

export const Clearable = (): JSXElement => {
    const dropdownId = useId('');
    const styles = useStyles();
    return (<div className={styles.root}>
      <Label htmlFor={dropdownId}>Pick a color</Label>
      <Dropdown clearable id={dropdownId} placeholder="Select a color">
        <Option>Red</Option>
        <Option>Green</Option>
        <Option>Blue</Option>
      </Dropdown>
    </div>);
};

export default Clearable;
```

## Complex Options

Source: Fluent, adapted for CoreAI.

Options are defined as JSX children, and can include nested elements or other components. When this is the case, the Option's `text` prop should be the plain text version of the option, and is used as the Dropdown button's value when the option is selected. Options should never contain interactive elements, such as buttons or links.

[Download source](/coreai-design-system/source/examples/components-dropdown--complex-options.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import { Persona } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '2px',
        maxWidth: '400px',
    },
});

export const ComplexOptions = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const dropdownId = useId('dropdown');
    const styles = useStyles();
    return (<div className={styles.root}>
      <label htmlFor={dropdownId}>Schedule a meeting</label>
      <Dropdown id={dropdownId} {...props}>
        <Option text="Katri Athokas">
          <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Katri Athokas" presence={{
            status: 'available',
        }} secondaryText="Available"/>
        </Option>
        <Option text="Elvia Atkins">
          <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Elvia Atkins" presence={{
            status: 'busy',
        }} secondaryText="Busy"/>
        </Option>
        <Option text="Cameron Evans">
          <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Cameron Evans" presence={{
            status: 'away',
        }} secondaryText="Away"/>
        </Option>
        <Option text="Wanda Howard">
          <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Wanda Howard" presence={{
            status: 'out-of-office',
        }} secondaryText="Out of office"/>
        </Option>
      </Dropdown>
    </div>);
};

export default ComplexOptions;
```

## Controlled

Source: Fluent, adapted for CoreAI.

A Dropdown may have controlled or controlled selection and value. When the selection is controlled or a default selection is provided, a controlled value or default value must also be defined. Otherwise, the Dropdown will not be able to display a value before the Options are rendered.

[Download source](/coreai-design-system/source/examples/components-dropdown--controlled.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import * as React from 'react';
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import { Persona } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        justifyItems: 'start',
        gap: '20px',
        maxWidth: '400px',
    },
    field: {
        display: 'grid',
        justifyItems: 'start',
        gap: '2px',
    },
});

export const Controlled = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const comboId = useId('combo-controlled');
    const styles = useStyles();
    const [selectedOptions, setSelectedOptions] = React.useState<string[]>(['eatkins']);
    const [value, setValue] = React.useState('Elvia Atkins');
    const onOptionSelect: (typeof props)['onOptionSelect'] = (ev, data) => {
        setSelectedOptions(data.selectedOptions);
        setValue(data.optionText ?? '');
    };
    return (<div className={styles.root}>
      <div className={styles.field}>
        <label htmlFor={`${comboId}-default`}>Schedule a meeting (default selection)</label>
        <Dropdown id={`${comboId}-default`} {...props} defaultValue="Elvia Atkins" defaultSelectedOptions={['eatkins']}>
          <Option text="Katri Athokas" value="kathok">
            <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Katri Athokas" presence={{
            status: 'available',
        }} secondaryText="Available"/>
          </Option>
          <Option text="Elvia Atkins" value="eatkins">
            <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Elvia Atkins" presence={{
            status: 'busy',
        }} secondaryText="Busy"/>
          </Option>
          <Option text="Cameron Evans" value="cevans">
            <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Cameron Evans" presence={{
            status: 'away',
        }} secondaryText="Away"/>
          </Option>
          <Option text="Wanda Howard" value="whoward">
            <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Wanda Howard" presence={{
            status: 'out-of-office',
        }} secondaryText="Out of office"/>
          </Option>
        </Dropdown>
      </div>

      <div className={styles.field}>
        <label htmlFor={`${comboId}-controlled`}>Schedule a meeting (controlled selection)</label>
        <Dropdown id={`${comboId}-controlled`} {...props} value={value} selectedOptions={selectedOptions} onOptionSelect={onOptionSelect}>
          <Option text="Katri Athokas" value="kathok">
            <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Katri Athokas" presence={{
            status: 'available',
        }} secondaryText="Available"/>
          </Option>
          <Option text="Elvia Atkins" value="eatkins">
            <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Elvia Atkins" presence={{
            status: 'busy',
        }} secondaryText="Busy"/>
          </Option>
          <Option text="Cameron Evans" value="cevans">
            <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Cameron Evans" presence={{
            status: 'away',
        }} secondaryText="Away"/>
          </Option>
          <Option text="Wanda Howard" value="whoward">
            <Persona avatar={{ color: 'colorful', 'aria-hidden': true }} name="Wanda Howard" presence={{
            status: 'out-of-office',
        }} secondaryText="Out of office"/>
          </Option>
        </Dropdown>
      </div>
    </div>);
};

export default Controlled;
```

## Controlling Open And Close

Source: Fluent, adapted for CoreAI.

The opening and close of the `Dropdown` can be controlled with your own state.
The `onOpenChange` callback will provide the hints for the state and triggers based on the appropriate
event.

_When controlling the open state of the `Dropdown`, extra effort is required to ensure that interactions are_
_still appropriate and that keyboard accessibility does not degrade._

[Download source](/coreai-design-system/source/examples/components-dropdown--controlling-open-and-close.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import * as React from 'react';
import type { DropdownProps } from "@coreai-ds/react-components";
import type { CheckboxProps } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { Checkbox } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '2px',
        maxWidth: '400px',
    },
});

export const ControllingOpenAndClose = (): JSXElement => {
    const styles = useStyles();
    const [open, setOpen] = React.useState(false);
    const handleOpenChange: DropdownProps['onOpenChange'] = (e, data) => setOpen(data.open);
    const onChange: CheckboxProps['onChange'] = (e, data) => setOpen(!!data.checked);
    const dropdownId = useId('dropdown');
    const options = ['Cat', 'Caterpillar', 'Corgi', 'Chupacabra', 'Dog', 'Ferret', 'Fish', 'Fox', 'Hamster', 'Snake'];
    return (<div className={styles.root}>
      <Checkbox value="open" name="state" label="open" checked={open} onChange={onChange}/>
      <label htmlFor={dropdownId}>Best pet</label>
      <Dropdown id={dropdownId} placeholder="Select an animal" open={open} onOpenChange={handleOpenChange}>
        {options.map(option => (<Option key={option} disabled={option === 'Ferret'}>
            {option}
          </Option>))}
      </Dropdown>
    </div>);
};

export default ControllingOpenAndClose;
```

## Custom Options

Source: Fluent, adapted for CoreAI.

Options and OptionGroups can be extended and customized.Here `OptionGroup` is wrapped in `CustomOptionGroup`,which adds a custom label style and takes an `options` array prop which is mapped to child Option elements.`Option` is also wrapped in `CustomOption`, which adds a custom check icon and animal icon.The `text` prop is added to `<Option>`, since the children of `<Option>` are not a simple string.

[Download source](/coreai-design-system/source/examples/components-dropdown--custom-options.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { AnimalCat24Filled } from "@fluentui/react-icons";
import { AnimalDog24Filled } from "@fluentui/react-icons";
import { AnimalRabbit24Filled } from "@fluentui/react-icons";
import { AnimalTurtle24Filled } from "@fluentui/react-icons";
import { FoodFish24Filled } from "@fluentui/react-icons";
import { makeStyles } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import type { OptionGroupProps } from "@coreai-ds/react-components";
import { OptionGroup } from "@coreai-ds/react-components";
import type { OptionProps } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import { CheckboxChecked24Regular } from "@fluentui/react-icons";
import * as React from 'react';

const animalIcons = {
    Cat: AnimalCat24Filled,
    Dog: AnimalDog24Filled,
    Rabbit: AnimalRabbit24Filled,
    Turtle: AnimalTurtle24Filled,
    Fish: FoodFish24Filled,
};

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '2px',
        maxWidth: '400px',
    },
    listbox: {
        maxHeight: '200px',
    },
});

type CustomOptionProps = Partial<OptionProps> & {
    animal: keyof typeof animalIcons;
};

const useCustomOptionStyles = makeStyles({
    option: {
        display: 'flex',
        alignItems: 'center',
        gap: '5px',
    },
    icon: { flex: '0 0 auto' },
    text: { flex: '1 1 auto' },
});

const CustomOption = (props: CustomOptionProps) => {
    const { animal, ...optionProps } = props;
    const Icon = animalIcons[animal];
    const styles = useCustomOptionStyles();
    return (<Option text={animal} className={styles.option} checkIcon={<CheckboxChecked24Regular />} {...optionProps}>
      <Icon className={styles.icon}/>
      <span className={styles.text}>{animal}</span>
    </Option>);
};

const CustomOptionGroup = (props: Partial<OptionGroupProps> & {
    options: (keyof typeof animalIcons)[];
}) => {
    const { label, options, ...optionGroupProps } = props;
    const labelSlot = typeof label === 'object' ? label : { children: label };
    return (<OptionGroup label={{ style: { fontStyle: 'italic' }, ...labelSlot }} {...optionGroupProps}>
      {options.map(option => (<CustomOption key={option} animal={option}/>))}
    </OptionGroup>);
};

export const CustomOptions = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const dropdownId = useId('dropdown');
    const land = ['Cat', 'Dog', 'Rabbit'] as (keyof typeof animalIcons)[];
    const water = ['Fish', 'Turtle'] as (keyof typeof animalIcons)[];
    const styles = useStyles();
    return (<div className={styles.root}>
      <label htmlFor={dropdownId}>Best pet</label>
      <Dropdown id={dropdownId} listbox={{ className: styles.listbox }} placeholder="Select an animal" {...props}>
        <CustomOptionGroup label="Land" options={land}/>
        <CustomOptionGroup label="Sea" options={water}/>
      </Dropdown>
    </div>);
};

export default CustomOptions;
```

## Disabled

Source: Fluent, adapted for CoreAI.

[Download source](/coreai-design-system/source/examples/components-dropdown--disabled.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '2px',
        maxWidth: '400px',
    },
});

export const Disabled = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const comboId = useId('combo-disabled');
    const options = ['Cat', 'Dog', 'Ferret', 'Fish', 'Hamster', 'Snake'];
    const styles = useStyles();
    return (<div className={styles.root}>
      <label htmlFor={comboId}>Best pet</label>
      <Dropdown id={comboId} disabled placeholder="Select an animal" {...props}>
        {options.map(option => (<Option key={option}>{option}</Option>))}
      </Dropdown>
    </div>);
};

export default Disabled;
```

## Grouped

Source: Fluent, adapted for CoreAI.

Dropdown options can be semantically grouped with the `OptionGroup` element, with an optional group label.

[Download source](/coreai-design-system/source/examples/components-dropdown--grouped.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import { OptionGroup } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '2px',
        maxWidth: '400px',
    },
});

export const Grouped = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const dropdownId = useId('dropdown-grouped');
    const land = ['Cat', 'Dog', 'Ferret', 'Hamster'];
    const water = ['Fish', 'Jellyfish', 'Octopus', 'Seal'];
    const styles = useStyles();
    return (<div className={styles.root}>
      <label htmlFor={dropdownId}>Best pet</label>
      <Dropdown id={dropdownId} placeholder="Select an animal" {...props}>
        <OptionGroup label="Land">
          {land.map(option => (<Option key={option} disabled={option === 'Ferret'}>
              {option}
            </Option>))}
        </OptionGroup>
        <OptionGroup label="Sea">
          {water.map(option => (<Option key={option}>{option}</Option>))}
        </OptionGroup>
      </Dropdown>
    </div>);
};

export default Grouped;
```

## Inline Label

Source: CoreAI.

[Download source](/coreai-design-system/source/examples/components-dropdown--inline-label.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as React from 'react';
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";

export const InlineLabel = () => {
    const statusOptions = ['Not started', 'In progress', 'Blocked', 'Completed'];
    const [status, setStatus] = React.useState<string>('');
    const [dynamicStatus, setDynamicStatus] = React.useState<string>('');
    const styles = /* css */ `
      .dropdown-inline-label-example {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        row-gap: var(--spacingVerticalL);
        max-width: 320px;
        padding: var(--spacingVerticalL);
      }

      .dropdown-inline-label-example__field {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        row-gap: var(--spacingVerticalXS);
      }

      .dropdown-inline-label-example__prop-label {
        font-family: var(--fontFamilyMonospace);
        font-size: var(--fontSizeBase200);
        color: var(--colorNeutralForeground3);
      }
    `;
    return (<>
        <style>{styles}</style>
        <div className="dropdown-inline-label-example">
          <div className="dropdown-inline-label-example__field">
            <code className="dropdown-inline-label-example__prop-label">label</code>
            <Dropdown label="Status" placeholder="Select a status" value={status} selectedOptions={status ? [status] : []} clearable onOptionSelect={(_event, data) => setStatus(data.optionValue ?? '')}>
              {statusOptions.map((option) => (<Option key={option}>{option}</Option>))}
            </Dropdown>
          </div>

          <div className="dropdown-inline-label-example__field">
            <code className="dropdown-inline-label-example__prop-label">label, dynamicWidth</code>
            <Dropdown label="Status" dynamicWidth value={dynamicStatus} selectedOptions={dynamicStatus ? [dynamicStatus] : []} clearable onOptionSelect={(_event, data) => setDynamicStatus(data.optionValue ?? '')}>
              {statusOptions.map((option) => (<Option key={option}>{option}</Option>))}
            </Dropdown>
          </div>
        </div>
      </>);
};

export default InlineLabel;
```

## Multiselect

Source: Fluent, adapted for CoreAI.

Dropdown supports multiselect, and options within a multiselect will display checkbox icons.

[Download source](/coreai-design-system/source/examples/components-dropdown--multiselect.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '2px',
        maxWidth: '400px',
    },
});

export const Multiselect = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const comboId = useId('combo-multi');
    const options = ['Cat', 'Dog', 'Ferret', 'Fish', 'Hamster', 'Snake'];
    const styles = useStyles();
    return (<div className={styles.root}>
      <label htmlFor={comboId}>Best pet</label>
      <Dropdown id={comboId} multiselect={true} placeholder="Select an animal" {...props}>
        {options.map(option => (<Option key={option} disabled={option === 'Ferret'}>
            {option}
          </Option>))}
      </Dropdown>
    </div>);
};

export default Multiselect;
```

## Size

Source: Fluent, adapted for CoreAI.

A Dropdown's size can be set to `small`, `medium` (default), or `large`.

[Download source](/coreai-design-system/source/examples/components-dropdown--size.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '20px',
        maxWidth: '400px',
        '> div': {
            display: 'grid',
            gridTemplateRows: 'repeat(1fr)',
            justifyItems: 'start',
            gap: '2px',
        },
    },
});

export const Size = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const comboId = useId('combobox');
    const styles = useStyles();
    return (<div className={styles.root}>
      <div>
        <h3>Small</h3>
        <label htmlFor={`${comboId}-small`}>Best pet</label>
        <Dropdown id={`${comboId}-small`} placeholder="Select an animal" size="small" {...props}>
          <Option>Cat</Option>
          <Option>Dog</Option>
          <Option>Bird</Option>
        </Dropdown>
      </div>

      <div>
        <h3>Medium</h3>
        <label htmlFor={`${comboId}-med`}>Best pet</label>
        <Dropdown id={`${comboId}-med`} placeholder="Select an animal" size="medium" {...props}>
          <Option>Cat</Option>
          <Option>Dog</Option>
          <Option>Bird</Option>
        </Dropdown>
      </div>

      <div>
        <h3>Large</h3>
        <label htmlFor={`${comboId}-large`}>Best pet</label>
        <Dropdown id={`${comboId}-large`} placeholder="Select an animal" size="large" {...props}>
          <Option>Cat</Option>
          <Option>Dog</Option>
          <Option>Bird</Option>
        </Dropdown>
      </div>
    </div>);
};

export default Size;
```

## Truncate

Source: CoreAI.

[Download source](/coreai-design-system/source/examples/components-dropdown--truncate.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as React from 'react';
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";

export const Truncate = () => {
    const longOptions = [
        'Awaiting stakeholder review and final sign-off',
        'Blocked by an upstream dependency in another team',
        'In progress — implementation roughly halfway complete',
        'Completed and deployed to the production environment',
    ];
    const [status, setStatus] = React.useState<string>(longOptions[0]);
    const styles = /* css */ `
      .dropdown-truncate-example {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        row-gap: var(--spacingVerticalL);
        max-width: 320px;
        padding: var(--spacingVerticalL);
      }

      .dropdown-truncate-example__field {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        row-gap: var(--spacingVerticalXS);
      }

      .dropdown-truncate-example__prop-label {
        font-family: var(--fontFamilyMonospace);
        font-size: var(--fontSizeBase200);
        color: var(--colorNeutralForeground3);
      }

      .dropdown-truncate-example__dropdown--narrow {
        width: 220px;
      }

      .dropdown-truncate-example__dropdown--narrower {
        width: 160px;
      }
    `;
    return (<>
        <style>{styles}</style>
        <div className="dropdown-truncate-example">
          <div className="dropdown-truncate-example__field">
            <code className="dropdown-truncate-example__prop-label">truncateTextOverflow</code>
            <Dropdown className="dropdown-truncate-example__dropdown--narrow" aria-label="Status" placeholder="Select a status" truncateTextOverflow value={status} selectedOptions={status ? [status] : []} clearable onOptionSelect={(_event, data) => setStatus(data.optionValue ?? '')}>
              {longOptions.map((option) => (<Option key={option}>{option}</Option>))}
            </Dropdown>
          </div>

          <div className="dropdown-truncate-example__field">
            <code className="dropdown-truncate-example__prop-label">truncateTextOverflow</code>
            <Dropdown className="dropdown-truncate-example__dropdown--narrower" aria-label="Status" placeholder="Select a status" truncateTextOverflow value={status} selectedOptions={status ? [status] : []} clearable onOptionSelect={(_event, data) => setStatus(data.optionValue ?? '')}>
              {longOptions.map((option) => (<Option key={option}>{option}</Option>))}
            </Dropdown>
          </div>
        </div>
      </>);
};

export default Truncate;
```

## Truncated Value

Source: Fluent, adapted for CoreAI.

The Dropdown button slot can be customized to render child JSX, which can be used to truncate the selected value text. Dropdown options can also be customized to overflow in various ways, e.g. by allowing long words to break and wrap.

[Download source](/coreai-design-system/source/examples/components-dropdown--truncated-value.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { useId } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import * as React from 'react';
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";

const useStyles = makeStyles({
    root: {
        // Stack the label above the field with a gap
        display: 'grid',
        gridTemplateRows: 'repeat(1fr)',
        justifyItems: 'start',
        gap: '2px',
        maxWidth: '200px',
    },
    listbox: {
        maxHeight: '200px',
    },
    // these styles wrap the value text within the dropdown button and cause it to truncate
    truncatedText: {
        overflowX: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap',
    },
    // these styles allow option text to break and wrap on long words, e.g. emails
    optionText: {
        overflow: 'hidden',
        overflowWrap: 'break-word',
    },
});

export const TruncatedValue = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const dropdownId = useId('dropdown');
    const options = [
        'Cat',
        'Caterpillar',
        'Corgi',
        'Chupacabra',
        'Dog',
        'Ferret',
        'Fish',
        'Fox',
        'Hamster',
        'Snake',
        'SuperLongName_123456789_SomeMoreStuffToMakeItLonger@fluentui.dev',
        'Screaming hairy armadillo (Chaetophractus vellerosus)',
    ];
    const styles = useStyles();
    const placeholder = 'Select an animal';
    // show truncated option by default
    const defaultValue = options[11];
    const [value, setValue] = React.useState(defaultValue);
    return (<div className={styles.root}>
      <label htmlFor={dropdownId}>Best pet</label>
      <Dropdown id={dropdownId} listbox={{ className: styles.listbox }} button={<span className={styles.truncatedText}>{value}</span>} onOptionSelect={(e, data) => setValue(data.optionText ?? placeholder)} defaultSelectedOptions={[defaultValue]} defaultValue={defaultValue} {...props}>
        {options.map(option => (<Option key={option} text={option} disabled={option === 'Ferret'}>
            <span className={styles.optionText}>{option}</span>
          </Option>))}
      </Dropdown>
    </div>);
};

export default TruncatedValue;
```

## With Field

Source: Fluent, adapted for CoreAI.

Field can be used with Dropdown to provide a label, description, error message, and more.

[Download source](/coreai-design-system/source/examples/components-dropdown--with-field.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { DropdownProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { Field } from "@coreai-ds/react-components";
import { Dropdown } from "@coreai-ds/react-components";
import { Option } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        maxWidth: '400px',
    },
});

export const WithField = (props: Partial<Omit<DropdownProps, "label" | "dynamicWidth">>): JSXElement => {
    const styles = useStyles();
    const options = ['Cat', 'Caterpillar', 'Corgi', 'Chupacabra', 'Dog', 'Ferret', 'Fish', 'Fox', 'Hamster', 'Snake'];
    return (<Field label="Best pet" required hint="Try picking 'Cat'" className={styles.root}>
      <Dropdown placeholder="Select an animal" {...props}>
        {options.map(option => (<Option key={option} disabled={option === 'Ferret'}>
            {option}
          </Option>))}
      </Dropdown>
    </Field>);
};

export default WithField;
```

## Resources

- [Figma component](https://www.figma.com/design/eXfSQrRg3poHRgmr0ivN5V/CoreAI-Figma-Library?node-id=324567-6252)
- [Fluent guidance](https://fluent2.microsoft.design/components/web/react/core/dropdown/usage)