> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Dropdown

> Action menus, searchable pickers, and form panels with shared presentation and interaction.

export const StoryEmbed = ({storyId, title, height = 120}) => <>
    <Tabs>
      <Tab title="Light">
        <iframe title={`${title} (light)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:light`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
      <Tab title="Dark">
        <iframe title={`${title} (dark)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:dark`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

`Dropdown` combines a positioned popup, visual rows, keyboard navigation, focus, and dismissal. Your application owns data, filtering, fetching and pagination. `SelectionGroup` owns independent selection values inside the popup. Import it from `twenty-ui/components`.

<StoryEmbed storyId="ui-components-dropdown--display" title="Dropdown actions" height={420} />

Dropdown.Content accepts numeric offsets or functions for `sideOffset` and `alignOffset`. Offset functions receive the anchor and popup dimensions, side, and alignment. Use them to preserve an anchored field picker’s overlap when the cell is scaled.

## Usage

```tsx theme={null}
import { Dropdown } from 'twenty-ui/components/navigation';
import { IconArchive, IconCopy, IconDownload } from 'twenty-ui/icon';
import { Button } from 'twenty-ui/primitives/input';

export const RecordActions = () => (
  <Dropdown.Root type="menu">
    <Dropdown.Trigger render={<Button>Record actions</Button>} />
    <Dropdown.Content aria-label="Record actions" width={240}>
      <Dropdown.Section>
        <Dropdown.ActionItem startIcon={<IconCopy />}>
          Duplicate
        </Dropdown.ActionItem>
        <Dropdown.Submenu>
          <Dropdown.SubmenuTrigger startIcon={<IconDownload />}>
            Export
          </Dropdown.SubmenuTrigger>
          <Dropdown.Content aria-label="Export formats">
            <Dropdown.Section>
              <Dropdown.ActionItem>CSV</Dropdown.ActionItem>
              <Dropdown.ActionItem>Excel</Dropdown.ActionItem>
            </Dropdown.Section>
          </Dropdown.Content>
        </Dropdown.Submenu>
      </Dropdown.Section>
      <Dropdown.Separator />
      <Dropdown.Section>
        <Dropdown.ActionItem startIcon={<IconArchive />}>
          Archive
        </Dropdown.ActionItem>
        <Dropdown.ActionItem
          render={
            <a href="#dropdown-documentation" aria-label="Documentation" />
          }
        >
          Documentation
        </Dropdown.ActionItem>
      </Dropdown.Section>
    </Dropdown.Content>
  </Dropdown.Root>
);
```

## Choose an interaction type

Set `type` on `Dropdown.Root` to match the popup's contents.

| Type | Content | Interaction |
| - | - | - |
| `menu` | Commands and navigation links | Menu semantics with arrow navigation and typeahead. |
| `picker` | Search, selectable values, and optional commands | A dialog containing search, selectable listboxes and optional commands. Arrow keys navigate result rows. |
| `panel` | Inputs, forms, and supporting actions | A dialog with native input behavior and Tab navigation. |

Pickers allow creation actions and independent selection groups in the same page, in any order. Each picker group is a listbox, and its options expose `aria-selected`. Menu groups use checked radio or checkbox menu items. Panel groups use buttons with `aria-pressed`. Commands retain their mode’s action semantics. Give each group and `Search` an accessible name. This custom picker is not a native Combobox.

`Content` takes its accessible name from `Trigger`, or from `SubmenuTrigger` in a submenu. Pass `aria-label` on `Content` when the trigger shows a value, such as the selected option, or when the root has no trigger. An explicit `aria-label` or `aria-labelledby`, and a `Title` inside a `Header`, take precedence over the trigger name.

[Select](/ui/primitives/input/select) and [Popover](/ui/primitives/surfaces/popover) remain available for direct composition.

## Anatomy

```text theme={null}
Dropdown.Root
├── Dropdown.Trigger
└── Dropdown.Content
    ├── Dropdown.Header
    │   ├── Dropdown.Close
    │   └── Dropdown.Title
    ├── Dropdown.Search
    └── Dropdown.Section
        ├── Dropdown.ActionItem
        └── Dropdown.SelectionGroup
            └── Dropdown.OptionItem
```

`Content` includes the portal and positioner. Use `width`, `side`, `align`, `sideOffset`, and `alignOffset` to control placement, and `collisionPadding` to keep the popup further from the edges of the viewport before it shifts or flips (5 pixels by default). `Section` groups rows with shared spacing, and `Separator` divides sections. A `scrollable` Section caps its height and scrolls; nest labelled sections inside it to scroll them as one list. Rows use [ListItem](/ui/primitives/navigation/list-item) for their appearance.

```tsx theme={null}
import { Dropdown } from 'twenty-ui/components/navigation';
import { IconCopy } from 'twenty-ui/icon';
import { Button } from 'twenty-ui/primitives/input';

export const RecordActions = ({ onDuplicate }: { onDuplicate: () => void }) => (
  <Dropdown.Root type="menu">
    <Dropdown.Trigger render={<Button>Record actions</Button>} />
    <Dropdown.Content>
      <Dropdown.Section>
        <Dropdown.ActionItem startIcon={<IconCopy />} onClick={onDuplicate}>
          Duplicate
        </Dropdown.ActionItem>
      </Dropdown.Section>
    </Dropdown.Content>
  </Dropdown.Root>
);
```

Pass custom trigger elements through `render` so the trigger remains one interactive element. Custom components must forward the supplied props and ref. `ActionItem` also accepts `render` for links.

## Item actions

`ActionItem` and `OptionItem` accept `actions` for trailing controls, such as a tab's edit button. Use them in `picker` and `panel` pages only: a `menu` may only contain menu items, so it cannot hold other controls. Set `actionsVisibility="always"` to keep them visible; the default is `"hover"`. Secondary controls render beside the primary row control and activate independently: they do not close the popup, so close it from the action's handler when needed. The `render` prop and ref still apply to the primary control, so it can also serve as a drag handle.

Use `tabIndex={-1}` for a pointer-only secondary action that has a separate keyboard alternative. Keyboard navigation continues to focus and activate the primary control.

## Headers

`Header` lays out a row at the top of the popup. Put a `Title` in it to name the popup after the title instead of the trigger. `Close` closes the popup the same way an outside press does. It renders an icon button with an X by default, so give it an `aria-label`, or pass `render` and children for another control. Other controls, such as a button that returns to a previous step, can sit in the same row. Use `Dropdown.Back` when navigating the root's page history.

## Search and selection

`Search` provides the input and navigation into the result rows. Pass `value` and `onValueChange`; compute or fetch matching results in your application. Render `Loading` while a request is pending and `Empty` when no results match. Both accept caller-provided status text.

<StoryEmbed storyId="ui-components-dropdown--picker-documentation" title="Searchable picker with inline creation" height={420} />

Wrap selectable options in `SelectionGroup` and give each option a stable `value` unique within the group. An uncontrolled group also needs an `id` unique within its dropdown tree, including submenus. Independently nested `Root` components keep their own selection store. Single selection uses a string or `null` for no selection. Multiple selection uses an array, including `[]` for no selection.

```tsx theme={null}
import { useState } from 'react';
import { Dropdown } from 'twenty-ui/components/navigation';
import { Button } from 'twenty-ui/primitives/input';

export const PersonPicker = () => {
  const [search, setSearch] = useState('');
  const [selectedPerson, setSelectedPerson] = useState<string | null>(null);
  const people = ['Ada Lovelace', 'Grace Hopper'].filter((person) =>
    person.toLowerCase().includes(search.toLowerCase()),
  );

  return (
    <Dropdown.Root type="picker">
      <Dropdown.Trigger render={<Button>Choose person</Button>} />
      <Dropdown.Content>
        <Dropdown.Search
          aria-label="Search people"
          value={search}
          onValueChange={setSearch}
        />
        <Dropdown.SelectionGroup
          id="person"
          aria-label="Person"
          value={selectedPerson}
          onValueChange={setSelectedPerson}
        >
          {people.map((person) => (
            <Dropdown.OptionItem key={person} value={person}>
              {person}
            </Dropdown.OptionItem>
          ))}
        </Dropdown.SelectionGroup>
      </Dropdown.Content>
    </Dropdown.Root>
  );
};
```

Pass `value` and `onValueChange` for controlled selection. Omitting `value`, or passing `undefined`, leaves selection uncontrolled; `defaultValue` sets its initial value. An uncontrolled group defaults to `null`, or `[]` with `multiple`. Its stable `id` preserves selection across close and reopen and across page navigation. Removing or filtering an option does not clear its selected identifier or emit a change; the option is selected again when it returns. Use a controlled value when the application needs to clear unavailable choices.

Each group changes independently. An option commits to its nearest group, while the active page supplies one ordered collection for arrow navigation across groups and action rows. Repeated activation of a selected single option preserves its value without another change callback. Multiple activation toggles the option in the array.

<StoryEmbed storyId="ui-components-dropdown--selection-groups-documentation" title="Independent owner and watcher selections" height={440} />

Single selection closes by default; multiple selection stays open. `SelectionGroup.closeOnSelect` changes the group default, and `OptionItem.closeOnSelect` overrides it for one option. Action rows use `closeOnClick` independently. A cancelled change preserves the previous selection and does not automatically close the popup.

`onValueChange` receives the next value and event details with `event`, `reason`, `trigger`, `cancel()` and `isCanceled`. The reason is `item-press`, and `event` is the original activation event. `OptionItem.onSelect` receives the same details before its owner commits. Call `cancel()` in either callback to prevent selection and automatic closing.

```tsx theme={null}
import { Dropdown } from 'twenty-ui/components/navigation';

<Dropdown.SelectionGroup
  id="watchers"
  aria-label="Watchers"
  multiple
  defaultValue={[]}
  onValueChange={(value, eventDetails) => {
    if (value.length > 3) {
      eventDetails.cancel();
    }
  }}
>
  <Dropdown.OptionItem value="ada">Ada Lovelace</Dropdown.OptionItem>
  <Dropdown.OptionItem value="grace">Grace Hopper</Dropdown.OptionItem>
</Dropdown.SelectionGroup>;
```

Search receives focus when the picker opens. Without search, the first enabled selected option receives focus, or the first enabled row when no selected option is present. While `Search` has focus and a nonempty query, the first eligible `OptionItem` across selection groups is highlighted and Enter activates it. Action rows are never picked this way. ArrowDown moves focus to the first enabled row, including actions. Leaving search clears the preview and `aria-activedescendant`, even when the popup stays open. Returning to search restores the preview for the current query.

Enter does nothing for an empty or whitespace-only query, or when no eligible option remains. Composing text with an input method does not activate an option or move focus with arrow keys. When rows are pinned above matches, such as the current value or a "none" row, render them only when they match the search text. The popup stays open when no option matches. Filtering remains caller-owned.

<StoryEmbed storyId="ui-components-dropdown--multiple-selection-documentation" title="Multiple selection" height={420} />

Standalone `OptionItem` still accepts `selected` and `onSelect` for callers that own selection themselves. Grouped options derive selection from the group value; do not duplicate that state on the option. Custom selection groups do not provide native form submission, reset, required validation, read-only behavior or Field integration. Use [Select](/ui/primitives/input/select) when those native form contracts are needed.

## Icon grids

<StoryEmbed storyId="ui-components-dropdown--icon-grid-documentation" title="Icon grid with selected cell styling" height={360} />

Set `columns` on `Section` to lay out items in equal-width grid columns. The same count drives keyboard navigation: Left and Right move within a row, while Up and Down move between rows. Navigation skips disabled options and follows the reading direction. When no enabled option is left in the column, Up and Down move to the nearest enabled option of the next row. Up from the first row returns to the search field when no earlier section exists. A short final row uses its last item when the requested column is missing. Inside a submenu, the backward arrow closes the submenu when no enabled option remains to its left.

Render each icon as an `OptionItem` with an accessible label and an icon button through `render`. Use `indicator="none"` to show selection through the button background. The `render` callback receives `{ selected, multiple, disabled }` state; use it to style a selected cell and forward the supplied props and ref.

```tsx theme={null}
import { LightIconButton } from 'twenty-ui/components/input';
import { Dropdown } from 'twenty-ui/components/navigation';
import { IconCalendar } from 'twenty-ui/icon';
import { Button } from 'twenty-ui/primitives/input';

export const IconGrid = () => (
  <Dropdown.Root type="picker">
    <Dropdown.Trigger render={<Button>Choose icon</Button>} />
    <Dropdown.Content>
      <Dropdown.SelectionGroup
        id="icon"
        aria-label="Icon"
        defaultValue="calendar"
      >
        <Dropdown.Section columns={5}>
          <Dropdown.OptionItem
            value="calendar"
            aria-label="Calendar"
            indicator="none"
            nativeButton
            render={(props, state) => (
              <LightIconButton
                // oxlint-disable-next-line react/jsx-props-no-spreading
                {...props}
                size="md"
                color={state.selected ? 'accent' : 'neutral'}
                aria-label="Calendar"
              >
                <IconCalendar />
              </LightIconButton>
            )}
          />
        </Dropdown.Section>
      </Dropdown.SelectionGroup>
    </Dropdown.Content>
  </Dropdown.Root>
);
```

## Keyboard focus

In `menu` and `picker` pages, the rows form a single Tab stop. Arrow keys move focus across sections, actions and options, and Home and End move to the first and last enabled rows unless the search field has focus. Moving focus never selects an option; Enter or Space activates the focused row. Tabbing back to the rows returns to the last focused row, or to the first enabled row once that row is gone. Search, `Back` beside a search, header buttons and other controls inside the popup keep their own Tab stops.

Tab and Shift+Tab close a `menu`, along with its parent menus when focus is in a submenu. In a `picker`, Tab moves through the popup's controls and closes the popup when focus leaves it. A `panel` keeps the native Tab order of its controls.

## Pages and submenus

Use `Page` for navigation that replaces the contents of the same popup. Wrap the first page in `Page id="root"`, or choose another initial page with `defaultPage`. Set `page` on an action to navigate without closing. `Back` returns to the previous page and restores focus to its invoking row. Closing the dropdown resets its page history.

A page can override the root's `type`. For example, an action menu can open a searchable picker page or a form panel. Search receives focus when entering a searchable page; other pages focus their first row after `Back`.

<StoryEmbed storyId="ui-components-dropdown--pages-documentation" title="Menu to picker page navigation" height={420} />

```tsx theme={null}
import { Dropdown } from 'twenty-ui/components/navigation';
import { Button } from 'twenty-ui/primitives/input';

export const FilterMenu = () => (
  <Dropdown.Root type="menu">
    <Dropdown.Trigger render={<Button>Filters</Button>} />
    <Dropdown.Content>
      <Dropdown.Page id="root">
        <Dropdown.Section>
          <Dropdown.ActionItem page="status">Status</Dropdown.ActionItem>
        </Dropdown.Section>
      </Dropdown.Page>
      <Dropdown.Page id="status" type="picker">
        <Dropdown.Back>Filters</Dropdown.Back>
        <Dropdown.Section>
          <Dropdown.SelectionGroup id="status" aria-label="Status">
            <Dropdown.OptionItem value="active">Active</Dropdown.OptionItem>
            <Dropdown.OptionItem value="archived">Archived</Dropdown.OptionItem>
          </Dropdown.SelectionGroup>
        </Dropdown.Section>
      </Dropdown.Page>
    </Dropdown.Content>
  </Dropdown.Root>
);
```

To navigate from code, call `useDropdownPage` in a component rendered inside the root. It returns the current `page`, `goToPage(page)`, `goBack()` and `canGoBack`. For example, an option can return to the previous page after a selection while the popup stays open:

```tsx theme={null}
import { Dropdown, useDropdownPage } from 'twenty-ui/components/navigation';

export const StatusOptions = ({
  status,
  onStatusChange,
}: {
  status: string | null;
  onStatusChange: (status: string | null) => void;
}) => {
  const { goBack } = useDropdownPage();

  return (
    <Dropdown.SelectionGroup
      id="status"
      aria-label="Status"
      value={status}
      closeOnSelect={false}
      onValueChange={(value) => {
        onStatusChange(value);
        goBack();
      }}
    >
      {['Active', 'Archived'].map((option) => (
        <Dropdown.OptionItem key={option} value={option}>
          {option}
        </Dropdown.OptionItem>
      ))}
    </Dropdown.SelectionGroup>
  );
};
```

Use `Submenu` with `SubmenuTrigger` and a nested `Content` for a side-by-side menu. Arrow Right enters the submenu; Arrow Left returns to its parent. Selecting a closing action closes the whole dropdown.

```text theme={null}
Dropdown.Content
└── Dropdown.Submenu
    ├── Dropdown.SubmenuTrigger
    └── Dropdown.Content
        └── Dropdown.ActionItem
```

## Independent nested pickers

Place another `Dropdown.Root` inside `Content` when a control opens its own picker, such as a sort direction selector. Selecting an inner option closes only that picker and restores focus to its trigger. Escape and outside presses dismiss one layer at a time. Use `Submenu` for commands that should close the entire menu tree when selected.

<StoryEmbed storyId="ui-components-dropdown--nested-documentation" title="Sort picker with a nested direction picker" height={420} />

## Panels and controlled state

Use `type="panel"` for form inputs. Input interaction keeps the panel open; a save action can close it. Own `open` and `onOpenChange` when another component or a shortcut needs to open the dropdown. Keep that state with the feature that coordinates the interaction.

<StoryEmbed storyId="ui-components-dropdown--panel-documentation" title="Controlled form panel" height={420} />

Escape dismisses the popup and restores focus to its trigger. Outside interaction also dismisses it, and the click that dismisses it doesn't activate what it lands on. Keys pressed inside the popup stay inside it, except Ctrl or Cmd shortcuts the dropdown doesn't handle, so page-level shortcuts keep working. `Content` accepts focus and portal options from Popover, including an explicit return-focus target for editor workflows.

## Dismissal

Escape, a press outside the popup and Tab out of it close the dropdown. Pass `onEscapeKeyDown` or `onInteractOutside` to `Root` to react before it closes, and call `event.preventDefault()` to keep it open. `event.target` is the element pressed outside, or `null` when focus leaves with Tab, and `event.type` is the type of the DOM event that triggered it, such as `touchmove` for a swipe outside the popup. A prevented outside press still reaches the element it lands on.

```tsx theme={null}
import { Dropdown } from 'twenty-ui/components/navigation';
import { Button } from 'twenty-ui/primitives/input';

export const ViewSettings = ({ isEditing }: { isEditing: boolean }) => (
  <Dropdown.Root
    type="panel"
    onInteractOutside={(event) => {
      if (isEditing) {
        event.preventDefault();
      }
    }}
  >
    <Dropdown.Trigger render={<Button>View settings</Button>} />
    <Dropdown.Content>
      <Dropdown.ActionItem>Save view</Dropdown.ActionItem>
    </Dropdown.Content>
  </Dropdown.Root>
);
```

## Anchoring without a trigger

A root can open without a `Trigger`, for example as a context menu. Control it with `open` and `onOpenChange`, and pass `anchor` to `Content`: an element, a ref, or a virtual element that returns a rectangle in viewport coordinates. Give `Content` an `aria-label`, since there is no trigger to name it after. On close, focus returns to the element that was focused when the popup opened.

<StoryEmbed storyId="ui-components-dropdown--context-menu-documentation" title="Context menu anchored to the pointer" height={420} />

```tsx theme={null}
import { useState } from 'react';
import { Dropdown } from 'twenty-ui/components/navigation';

export const RecordContextMenu = ({ recordName }: { recordName: string }) => {
  const [open, setOpen] = useState(false);
  const [point, setPoint] = useState({ x: 0, y: 0 });

  return (
    <>
      <p
        onContextMenu={(event) => {
          event.preventDefault();
          setPoint({ x: event.clientX, y: event.clientY });
          setOpen(true);
        }}
      >
        {recordName}
      </p>
      <Dropdown.Root type="menu" open={open} onOpenChange={setOpen}>
        <Dropdown.Content
          aria-label="Record actions"
          anchor={{
            getBoundingClientRect: () => new DOMRect(point.x, point.y, 0, 0),
          }}
        >
          <Dropdown.ActionItem>Duplicate</Dropdown.ActionItem>
        </Dropdown.Content>
      </Dropdown.Root>
    </>
  );
};
```

Right-clicking elsewhere while the menu is open moves it to the new point.

## Labels

Each part owns its text: supply `Search.placeholder` and native accessible names, `Close` accessible attributes, and children for `Back`, `Loading`, and `Empty`. `Back` defaults to `Back`; loading and empty states have no built-in message. Item parts accept `shortcutJoinLabel` to replace the default `then` between sequential shortcut steps. Native `aria-labelledby` takes precedence over `aria-label`.

## Props

### Dropdown.Root

<ParamField body="Root.defaultOpen" type="boolean">
  Whether the popup is initially open when uncontrolled.
</ParamField>

<ParamField body="Root.defaultPage" type="string">
  ID of the `Page` shown when the popup opens. Closing the popup resets the page history to it. Defaults to `root`.
</ParamField>

<ParamField body="Root.multiple" type="boolean">
  Default for standalone options. Use `SelectionGroup.multiple` for independently owned selection values.
</ParamField>

<ParamField body="Root.onEscapeKeyDown" type="((event: DropdownDismissEvent) => void)">
  Called when Escape is about to close the popup. Call `event.preventDefault()` to keep it open.
</ParamField>

<ParamField body="Root.onInteractOutside" type="((event: DropdownDismissEvent) => void)">
  Called when a press outside the popup, or Tab out of it, is about to close it. `event.target` is the element pressed outside, or `null` after Tab, and `event.type` is the type of the DOM event that triggered it. Call `event.preventDefault()` to keep it open.
</ParamField>

<ParamField body="Root.onOpenChange" type="((open: boolean) => void)">
  Called with the next open state when the popup opens or closes.
</ParamField>

<ParamField body="Root.open" type="boolean">
  Whether the popup is open. Use with `onOpenChange` to control it.
</ParamField>

<ParamField body="Root.type" type="&#x22;menu&#x22; | &#x22;panel&#x22; | &#x22;picker&#x22;" required>
  Interaction model: `menu` for commands and links, `picker` for search and selectable options, or `panel` for forms. It sets the ARIA roles, initial focus, and keyboard navigation.
</ParamField>

### Dropdown.Trigger

<ParamField body="Trigger.className" type="string | ((state: PopoverTriggerState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Trigger.closeDelay" type="number" default="0">
  How long to wait before closing the popover that was opened on hover.
  Specified in milliseconds.

  Requires the `openOnHover` prop.
</ParamField>

<ParamField body="Trigger.delay" type="number" default="300">
  How long to wait before the popover may be opened on hover. Specified in milliseconds.

  Requires the `openOnHover` prop.
</ParamField>

<ParamField body="Trigger.id" type="string">
  ID of the trigger. In addition to being forwarded to the rendered element,
  it is also used to specify the active trigger for the popover in controlled mode (with the PopoverRoot `triggerId` prop).
</ParamField>

<ParamField body="Trigger.nativeButton" type="boolean" default="true">
  Whether the component renders a native `<button>` element when replacing it
  via the `render` prop.
  Set to `false` if the rendered element is not a button (e.g. `<div>`).
</ParamField>

<ParamField body="Trigger.openOnHover" type="boolean" default="false">
  Whether the popover should also open when the trigger is hovered.
</ParamField>

<ParamField body="Trigger.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, PopoverTriggerState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Trigger.style" type="CSSProperties | ((state: PopoverTriggerState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### Dropdown.Content

<ParamField body="Content.align" type="&#x22;center&#x22; | &#x22;end&#x22; | &#x22;start&#x22;" default="start">
  Alignment along the anchor. Defaults to start.
</ParamField>

<ParamField body="Content.alignOffset" type="number | OffsetFunction" default="0">
  Offset along the alignment axis. Accepts a number or positioning function.
</ParamField>

<ParamField body="Content.anchor" type="Element | VirtualElement | RefObject<Element | null> | (() => Element | VirtualElement | null) | null">
  An element to position the popup against.
  By default, the popup will be positioned against the trigger.
</ParamField>

<ParamField body="Content.className" type="string | ((state: PopoverPopupState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Content.collisionPadding" type="Padding" default="5">
  Additional space to maintain from the edge of the collision boundary.
</ParamField>

<ParamField body="Content.container" type="HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null">
  Portal destination, using the scoped theme when omitted. Explicit null waits for a target, matching Popover.Portal.
</ParamField>

<ParamField body="Content.finalFocus" type="boolean | RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | void | HTMLElement | null)">
  Determines the element to focus when the popover is closed.

  * `false`: Do not move focus.
  * `true`: Move focus based on the default behavior (trigger or previously focused element).
  * `RefObject`: Move focus to the ref element.
  * `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
    Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing.
</ParamField>

<ParamField body="Content.initialFocus" type="boolean | RefObject<HTMLElement | null> | ((openType: InteractionType) => boolean | void | HTMLElement | null)">
  Determines the element to focus when the popover is opened.
  By default, focus moves to the first tabbable element inside the popup, except when the popover
  is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.

  * `false`: Do not move focus.
  * `true`: Move focus based on the default behavior (first tabbable element or popup).
  * `RefObject`: Move focus to the ref element.
  * `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`).
    Return an element to focus, `true` to use the default behavior, `null` to fall back to the default behavior, or `false`/`undefined` to do nothing.
</ParamField>

<ParamField body="Content.keepMounted" type="boolean" default="false">
  Keeps the popup mounted while closed.
</ParamField>

<ParamField body="Content.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, PopoverPopupState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Content.side" type="&#x22;bottom&#x22; | &#x22;inline-end&#x22; | &#x22;inline-start&#x22; | &#x22;left&#x22; | &#x22;right&#x22; | &#x22;top&#x22;" default="bottom">
  Preferred side of the anchor. Defaults to bottom, or inline-end in a submenu.
</ParamField>

<ParamField body="Content.sideOffset" type="number | OffsetFunction" default="0">
  Distance from the anchor. Defaults to 0. Accepts a number or positioning function.
</ParamField>

<ParamField body="Content.style" type="CSSProperties | ((state: PopoverPopupState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

<ParamField body="Content.width" type="Width<string | number>" default="200">
  CSS width of the popup. Numbers are in pixels.
</ParamField>

### Dropdown.ActionItem

<ParamField body="ActionItem.actions" type="ReactNode">
  Trailing controls rendered beside the primary row control. Only supported in picker and panel pages, since a menu may only contain menu items. Secondary actions activate independently of the row.
</ParamField>

<ParamField body="ActionItem.actionsVisibility" type="&#x22;always&#x22; | &#x22;hover&#x22;">
  Whether trailing actions appear on hover or remain visible. Defaults to `hover`.
</ParamField>

<ParamField body="ActionItem.className" type="string">
  CSS class applied to the row.
</ParamField>

<ParamField body="ActionItem.closeOnClick" type="boolean" default="true">
  Closes the dropdown after activation, along with parent menus when inside a submenu. Ignored when `page` is set.
</ParamField>

<ParamField body="ActionItem.color" type="&#x22;danger&#x22; | &#x22;neutral&#x22;">
  Color of the text and icons. `danger` marks a destructive action.
</ParamField>

<ParamField body="ActionItem.description" type="ReactNode">
  Supporting text, placed according to `descriptionPlacement`.
</ParamField>

<ParamField body="ActionItem.descriptionPlacement" type="&#x22;end&#x22; | &#x22;inline&#x22;">
  Where the description renders: inline after the content or at the end of
  the row.
</ParamField>

<ParamField body="ActionItem.endIcon" type="ReactNode">
  Icon rendered after the content.
</ParamField>

<ParamField body="ActionItem.focusableWhenDisabled" type="boolean" default="false">
  Whether the button should be focusable when disabled.
</ParamField>

<ParamField body="ActionItem.hasSubmenu" type="boolean">
  Shows a chevron indicating that the item opens a submenu.
</ParamField>

<ParamField body="ActionItem.nativeButton" type="boolean" default="true when render is omitted; false otherwise">
  Whether the component renders a native `<button>` element when replacing it
  via the `render` prop.
  Set to `false` if the rendered element is not a button (for example, `<div>`).
</ParamField>

<ParamField body="ActionItem.page" type="string">
  ID of the `Page` to show on activation. The popup stays open, and the row shows a chevron by default.
</ParamField>

<ParamField body="ActionItem.render" type="ReactElement<unknown, string | JSXElementConstructor<any>>">
  Element rendered as the row instead of a native button. Custom components must forward the supplied props and ref.
</ParamField>

<ParamField body="ActionItem.shortcut" type="ShortcutDefinition">
  Keyboard shortcut keys displayed at the end of the row. Registering the
  shortcut is up to the application.
</ParamField>

<ParamField body="ActionItem.shortcutJoinLabel" type="string">
  Text between sequential shortcut steps. Defaults to `then`.
</ParamField>

<ParamField body="ActionItem.startIcon" type="ReactNode">
  Icon rendered before the content.
</ParamField>

<ParamField body="ActionItem.style" type="CSSProperties">
  Inline styles applied to the row.
</ParamField>

### Dropdown.OptionItem

<ParamField body="OptionItem.actions" type="ReactNode">
  Trailing controls rendered beside the primary row control. Only supported in picker and panel pages, since a menu may only contain menu items. Secondary actions activate independently of the row.
</ParamField>

<ParamField body="OptionItem.actionsVisibility" type="&#x22;always&#x22; | &#x22;hover&#x22;">
  Whether trailing actions appear on hover or remain visible. Defaults to `hover`.
</ParamField>

<ParamField body="OptionItem.className" type="string">
  CSS class applied to the row.
</ParamField>

<ParamField body="OptionItem.closeOnSelect" type="boolean">
  Overrides the nearest group close policy for this option. A cancelled selection never closes automatically.
</ParamField>

<ParamField body="OptionItem.color" type="&#x22;danger&#x22; | &#x22;neutral&#x22;">
  Color of the text and icons. `danger` marks a destructive action.
</ParamField>

<ParamField body="OptionItem.description" type="ReactNode">
  Supporting text, placed according to `descriptionPlacement`.
</ParamField>

<ParamField body="OptionItem.descriptionPlacement" type="&#x22;end&#x22; | &#x22;inline&#x22;">
  Where the description renders: inline after the content or at the end of
  the row.
</ParamField>

<ParamField body="OptionItem.endIcon" type="ReactNode">
  Icon rendered after the content.
</ParamField>

<ParamField body="OptionItem.focusableWhenDisabled" type="boolean" default="false">
  Whether the button should be focusable when disabled.
</ParamField>

<ParamField body="OptionItem.hasSubmenu" type="boolean">
  Shows a chevron indicating that the item opens a submenu.
</ParamField>

<ParamField body="OptionItem.indicator" type="&#x22;check&#x22; | &#x22;checkbox&#x22; | &#x22;none&#x22;">
  Selection indicator: a check icon after the content, a checkbox before it, or none. Defaults to `checkbox` when `multiple` is set, otherwise `check`, and to `none` when `selected` is omitted.
</ParamField>

<ParamField body="OptionItem.nativeButton" type="boolean" default="true when render is omitted; false otherwise">
  Whether the component renders a native `<button>` element when replacing it
  via the `render` prop.
  Set to `false` if the rendered element is not a button (for example, `<div>`).
</ParamField>

<ParamField body="OptionItem.onSelect" type="((eventDetails: DropdownSelectionGroupChangeEventDetails) => void)">
  Called before the nearest group commits selection, with `event`, `reason`, `trigger`, `cancel` and `isCanceled`. Calling `cancel()` prevents the value change and automatic close.
</ParamField>

<ParamField body="OptionItem.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DropdownOptionItemState>">
  Element or function rendered as the row. Functions receive the supplied props and `{ selected, multiple, disabled }` state. Forward the props and ref to the rendered control.
</ParamField>

<ParamField body="OptionItem.selected" type="boolean">
  Selected state for standalone options. Options inside a `SelectionGroup` derive it from their owner. Grouped picker options expose `aria-selected`, menu options expose `aria-checked`, and panel options expose `aria-pressed`.
</ParamField>

<ParamField body="OptionItem.shortcut" type="ShortcutDefinition">
  Keyboard shortcut keys displayed at the end of the row. Registering the
  shortcut is up to the application.
</ParamField>

<ParamField body="OptionItem.shortcutJoinLabel" type="string">
  Text between sequential shortcut steps. Defaults to `then`.
</ParamField>

<ParamField body="OptionItem.startIcon" type="ReactNode">
  Icon rendered before the content.
</ParamField>

<ParamField body="OptionItem.style" type="CSSProperties">
  Inline styles applied to the row.
</ParamField>

<ParamField body="OptionItem.value" type="string">
  Stable option identifier within its nearest `SelectionGroup`. The group supplies selected state and commits this value on activation.
</ParamField>

### Dropdown.SelectionGroup

<ParamField body="SelectionGroup.closeOnSelect" type="boolean">
  Default close policy for owned options: true for single selection, false for multiple selection. Individual options can override it.
</ParamField>

<ParamField body="SelectionGroup.defaultValue" type="string | string[] | null">
  Initial uncontrolled selection. Defaults to null for single selection and an empty array for multiple selection.
</ParamField>

<ParamField body="SelectionGroup.id" type="string">
  Stable identifier unique within the dropdown root. Required for uncontrolled groups, whose values persist under it across popup close and page navigation. Optional for controlled groups.
</ParamField>

<ParamField body="SelectionGroup.multiple" type="boolean">
  Uses an array of selected identifiers when true. Otherwise the value is one identifier or null.
</ParamField>

<ParamField body="SelectionGroup.onValueChange" type="((value: string | null, eventDetails: DropdownSelectionGroupChangeEventDetails) => void) | ((value: string[], eventDetails: DropdownSelectionGroupChangeEventDetails) => void)">
  Called with the next value and cancellable event details: `event`, `reason`, `trigger`, `cancel` and `isCanceled`. Calling `cancel()` preserves the value and keeps the popup open. Repeated single selection does not emit another change.
</ParamField>

<ParamField body="SelectionGroup.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DropdownSelectionGroupState>">
  Element or function rendered as the group. Functions receive supplied props and `{ value, multiple }` state. Forward the props and ref.
</ParamField>

<ParamField body="SelectionGroup.value" type="string | string[] | null">
  Controlled selection: a string or null for single selection, or an array for multiple selection. Undefined leaves selection uncontrolled.
</ParamField>

### Dropdown.Search

<ParamField body="Search.className" type="string | ((state: InputState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Search.defaultValue" type="string | number | readonly string[]">
  The default value of the input. Use when uncontrolled.
</ParamField>

<ParamField body="Search.onValueChange" type="((value: string) => void)">
  Called with the search text on every change. The application filters the results.
</ParamField>

<ParamField body="Search.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, InputState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Search.style" type="CSSProperties | ((state: InputState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

<ParamField body="Search.value" type="string | number | readonly string[]">
  The value of the input. Use when controlled.
</ParamField>

### Dropdown.Header

<ParamField body="Header.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

### Dropdown.Title

<ParamField body="Title.className" type="string | ((state: PopoverTitleState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Title.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, PopoverTitleState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Title.style" type="CSSProperties | ((state: PopoverTitleState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### Dropdown.Close

<ParamField body="Close.aria-label" type="string" required>
  Accessible name of the close control. Required because the default control only shows an icon.
</ParamField>

<ParamField body="Close.className" type="string | ((state: PopoverCloseState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Close.nativeButton" type="boolean" default="true">
  Whether the component renders a native `<button>` element when replacing it
  via the `render` prop.
  Set to `false` if the rendered element is not a button (for example, `<div>`).
</ParamField>

<ParamField body="Close.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, PopoverCloseState>">
  Allows you to replace the component's HTML element
  with a different tag, or compose it with another component.

  Accepts a `ReactElement` or a function that returns the element to render.
</ParamField>

<ParamField body="Close.style" type="CSSProperties | ((state: PopoverCloseState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### Dropdown.Page

<ParamField body="Page.id" type="string" required>
  Identifier matched by `defaultPage`, the `page` prop of actions, and `goToPage`. The page renders only while it is current.
</ParamField>

<ParamField body="Page.type" type="&#x22;menu&#x22; | &#x22;panel&#x22; | &#x22;picker&#x22;">
  Interaction model while the page is shown. Defaults to the root `type`.
</ParamField>

### Dropdown.Back

<ParamField body="Back.className" type="string">
  CSS class applied to the row.
</ParamField>

<ParamField body="Back.color" type="&#x22;danger&#x22; | &#x22;neutral&#x22;">
  Color of the text and icons. `danger` marks a destructive action.
</ParamField>

<ParamField body="Back.description" type="ReactNode">
  Supporting text, placed according to `descriptionPlacement`.
</ParamField>

<ParamField body="Back.descriptionPlacement" type="&#x22;end&#x22; | &#x22;inline&#x22;">
  Where the description renders: inline after the content or at the end of
  the row.
</ParamField>

<ParamField body="Back.endIcon" type="ReactNode">
  Icon rendered after the content.
</ParamField>

<ParamField body="Back.focusableWhenDisabled" type="boolean" default="false">
  Whether the button should be focusable when disabled.
</ParamField>

<ParamField body="Back.hasSubmenu" type="boolean">
  Shows a chevron indicating that the item opens a submenu.
</ParamField>

<ParamField body="Back.nativeButton" type="boolean" default="true when render is omitted; false otherwise">
  Whether the component renders a native `<button>` element when replacing it
  via the `render` prop.
  Set to `false` if the rendered element is not a button (for example, `<div>`).
</ParamField>

<ParamField body="Back.render" type="ReactElement<unknown, string | JSXElementConstructor<any>>">
  Element rendered as the row instead of a native button. Custom components must forward the supplied props and ref.
</ParamField>

<ParamField body="Back.shortcut" type="ShortcutDefinition">
  Keyboard shortcut keys displayed at the end of the row. Registering the
  shortcut is up to the application.
</ParamField>

<ParamField body="Back.shortcutJoinLabel" type="string">
  Text between sequential shortcut steps. Defaults to `then`.
</ParamField>

<ParamField body="Back.startIcon" type="ReactNode">
  Icon rendered before the content.
</ParamField>

<ParamField body="Back.style" type="CSSProperties">
  Inline styles applied to the row.
</ParamField>

### Dropdown.Submenu

<ParamField body="Submenu.defaultOpen" type="boolean">
  Whether the popup is initially open when uncontrolled.
</ParamField>

<ParamField body="Submenu.defaultPage" type="string">
  ID of the `Page` shown when the popup opens. Closing the popup resets the page history to it. Defaults to `root`.
</ParamField>

<ParamField body="Submenu.multiple" type="boolean">
  Default for standalone options. Use `SelectionGroup.multiple` for independently owned selection values.
</ParamField>

<ParamField body="Submenu.onOpenChange" type="((open: boolean) => void)">
  Called with the next open state when the popup opens or closes.
</ParamField>

<ParamField body="Submenu.open" type="boolean">
  Whether the popup is open. Use with `onOpenChange` to control it.
</ParamField>

<ParamField body="Submenu.type" type="&#x22;menu&#x22; | &#x22;panel&#x22; | &#x22;picker&#x22;" default="menu">
  Interaction model: `menu` for commands and links, `picker` for search and selectable options, or `panel` for forms. It sets the ARIA roles, initial focus, and keyboard navigation.
</ParamField>

### Dropdown.SubmenuTrigger

<ParamField body="SubmenuTrigger.className" type="string">
  CSS class applied to the row.
</ParamField>

<ParamField body="SubmenuTrigger.closeDelay" type="number">
  Delay in milliseconds before a submenu opened on hover closes. Requires `openOnHover`. Defaults to `0`.
</ParamField>

<ParamField body="SubmenuTrigger.color" type="&#x22;danger&#x22; | &#x22;neutral&#x22;">
  Color of the text and icons. `danger` marks a destructive action.
</ParamField>

<ParamField body="SubmenuTrigger.delay" type="number">
  Delay in milliseconds before the submenu opens on hover. Requires `openOnHover`. Defaults to `300`.
</ParamField>

<ParamField body="SubmenuTrigger.description" type="ReactNode">
  Supporting text, placed according to `descriptionPlacement`.
</ParamField>

<ParamField body="SubmenuTrigger.descriptionPlacement" type="&#x22;end&#x22; | &#x22;inline&#x22;">
  Where the description renders: inline after the content or at the end of
  the row.
</ParamField>

<ParamField body="SubmenuTrigger.endIcon" type="ReactNode">
  Icon rendered after the content.
</ParamField>

<ParamField body="SubmenuTrigger.focusableWhenDisabled" type="boolean" default="false">
  Whether the button should be focusable when disabled.
</ParamField>

<ParamField body="SubmenuTrigger.hasSubmenu" type="boolean" default="true">
  Shows a chevron indicating that the item opens a submenu.
</ParamField>

<ParamField body="SubmenuTrigger.nativeButton" type="boolean" default="true when render is omitted; false otherwise">
  Whether the component renders a native `<button>` element when replacing it
  via the `render` prop.
  Set to `false` if the rendered element is not a button (for example, `<div>`).
</ParamField>

<ParamField body="SubmenuTrigger.openOnHover" type="boolean" default="true">
  Also opens the submenu when the row is hovered.
</ParamField>

<ParamField body="SubmenuTrigger.render" type="ReactElement<unknown, string | JSXElementConstructor<any>>">
  Element rendered as the row instead of a native button. Custom components must forward the supplied props and ref.
</ParamField>

<ParamField body="SubmenuTrigger.shortcut" type="ShortcutDefinition">
  Keyboard shortcut keys displayed at the end of the row. Registering the
  shortcut is up to the application.
</ParamField>

<ParamField body="SubmenuTrigger.shortcutJoinLabel" type="string">
  Text between sequential shortcut steps. Defaults to `then`.
</ParamField>

<ParamField body="SubmenuTrigger.startIcon" type="ReactNode">
  Icon rendered before the content.
</ParamField>

<ParamField body="SubmenuTrigger.style" type="CSSProperties">
  Inline styles applied to the row.
</ParamField>

### Dropdown.Section

<ParamField body="Section.columns" type="number">
  Number of grid columns. Sets the grid layout and enables horizontal arrow navigation and vertical movement by row.
</ParamField>

<ParamField body="Section.label" type="ReactNode">
  Heading displayed above the rows. It also names the group for assistive technologies.
</ParamField>

<ParamField body="Section.scrollable" type="boolean">
  Caps the section height and scrolls its rows. Nest labelled sections inside it to scroll them as one list.
</ParamField>

### Dropdown.Separator

<ParamField body="Separator.className" type="string">
  Class applied to the separator. Native div attributes and refs are also accepted.
</ParamField>

### Dropdown.Loading

<ParamField body="Loading.children" type="ReactNode">
  Loading message announced as a polite, busy status.
</ParamField>

<ParamField body="Loading.className" type="string">
  Class applied to the status. Native div attributes and refs are also accepted.
</ParamField>

### Dropdown.Empty

<ParamField body="Empty.children" type="ReactNode">
  Empty-state message announced as a polite status.
</ParamField>

<ParamField body="Empty.className" type="string">
  Class applied to the status. Native div attributes and refs are also accepted.
</ParamField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.