Skip to main content
Dropdown combines a positioned popup, visual rows, keyboard navigation, focus, and dismissal. Your application owns data, filtering, fetching, pagination, and selected values. Import it from twenty-ui/components.

Choose an interaction type

Set type on Dropdown.Root to match the popup’s contents. Pickers allow creation actions and selectable values in the same list, in any order. Options expose their selected state with aria-pressed; commands keep their button semantics. Use a descriptive accessible name on Content and Search. The underlying Menu, Select, and Popover remain available for direct composition.

Anatomy

Content includes the portal and positioner. Use width, side, align, sideOffset, and alignOffset to control placement. Section groups rows with shared spacing, and Separator divides sections. Rows use ListItem for their appearance.
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.

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.
Actions and single selection close by default. Set multiple on the root to keep option selection open. The application still owns the selected values. closeOnClick on actions and closeOnSelect on options override those defaults, including repeated actions or asynchronous progress. Use disabled to prevent activation while retaining the row’s appearance.

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

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. Escape dismisses the popup and restores focus to its trigger. Outside interaction also dismisses it. Content accepts focus and portal options from Popover, including an explicit return-focus target for editor workflows.

Props

boolean
string
boolean
((open: boolean) => void)
boolean
"menu" | "panel" | "picker"
required
string | ((state: PopoverTriggerState) => string | undefined)
CSS class applied to the element, or a function that returns a class based on the component’s state.
number
default:"0"
How long to wait before closing the popover that was opened on hover. Specified in milliseconds.Requires the openOnHover prop.
number
default:"300"
How long to wait before the popover may be opened on hover. Specified in milliseconds.Requires the openOnHover prop.
PopoverHandle<unknown>
A handle to associate the trigger with a popover.
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).
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>).
boolean
default:"false"
Whether the popover should also open when the trigger is hovered.
unknown
A payload to pass to the popover when it is opened.
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.
CSSProperties | ((state: PopoverTriggerState) => CSSProperties | undefined)
Style applied to the element, or a function that returns a style object based on the component’s state.
"center" | "end" | "start"
default:"start"
Alignment of the popup along the anchor.
number
Offset in pixels along the alignment axis.
Element | VirtualElement | RefObject<Element | null> | (() => Element | VirtualElement | null) | null
Element or position the popup is anchored to. Defaults to the trigger.
string | ((state: PopoverPopupState) => string | undefined)
CSS class applied to the element, or a function that returns a class based on the component’s state.
HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null
Element the popup is portaled into. Defaults to the theme’s portal container.
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.
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.
boolean
Keeps the popup mounted in the DOM while the popover is closed.
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.
"bottom" | "inline-end" | "inline-start" | "left" | "right" | "top"
Side of the anchor the popup is placed on.
number
default:"0"
Distance in pixels between the anchor and the popup.
CSSProperties | ((state: PopoverPopupState) => CSSProperties | undefined)
Style applied to the element, or a function that returns a style object based on the component’s state.
Width<string | number>
default:"200"
string
boolean
default:"true"
"danger" | "neutral"
Color of the text and icons. danger marks a destructive action.
ReactNode
Supporting text, placed according to descriptionPlacement.
"end" | "inline"
Where the description renders: inline after the content or at the end of the row.
ReactNode
Icon rendered after the content.
boolean
default:"false"
Whether the button should be focusable when disabled.
boolean
Shows a chevron indicating that the item opens a submenu.
string[]
Keyboard shortcut keys displayed at the end of the row. Registering the shortcut is up to the application.
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>).
string
ReactElement<unknown, string | JSXElementConstructor<any>>
ReactNode
Icon rendered before the content.
CSSProperties
string
boolean
"danger" | "neutral"
Color of the text and icons. danger marks a destructive action.
ReactNode
Supporting text, placed according to descriptionPlacement.
"end" | "inline"
Where the description renders: inline after the content or at the end of the row.
ReactNode
Icon rendered after the content.
boolean
default:"false"
Whether the button should be focusable when disabled.
boolean
Shows a chevron indicating that the item opens a submenu.
string[]
Keyboard shortcut keys displayed at the end of the row. Registering the shortcut is up to the application.
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>).
(() => void)
ReactElement<unknown, string | JSXElementConstructor<any>>
boolean
required
ReactNode
Icon rendered before the content.
CSSProperties
string | ((state: InputState) => string | undefined)
CSS class applied to the element, or a function that returns a class based on the component’s state.
string | number | readonly string[]
The default value of the input. Use when uncontrolled.
((value: string) => void)
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.
CSSProperties | ((state: InputState) => CSSProperties | undefined)
Style applied to the element, or a function that returns a style object based on the component’s state.
string | number | readonly string[]
The value of the input. Use when controlled.
string
required
"menu" | "panel" | "picker"
string
"danger" | "neutral"
Color of the text and icons. danger marks a destructive action.
ReactNode
Supporting text, placed according to descriptionPlacement.
"end" | "inline"
Where the description renders: inline after the content or at the end of the row.
ReactNode
Icon rendered after the content.
boolean
default:"false"
Whether the button should be focusable when disabled.
boolean
Shows a chevron indicating that the item opens a submenu.
string[]
Keyboard shortcut keys displayed at the end of the row. Registering the shortcut is up to the application.
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>).
ReactElement<unknown, string | JSXElementConstructor<any>>
ReactNode
Icon rendered before the content.
CSSProperties
boolean
string
boolean
((open: boolean) => void)
boolean
"menu" | "panel" | "picker"
default:"menu"
string
number
"danger" | "neutral"
Color of the text and icons. danger marks a destructive action.
number
ReactNode
Supporting text, placed according to descriptionPlacement.
"end" | "inline"
Where the description renders: inline after the content or at the end of the row.
ReactNode
Icon rendered after the content.
boolean
default:"false"
Whether the button should be focusable when disabled.
boolean
default:"true"
Shows a chevron indicating that the item opens a submenu.
string[]
Keyboard shortcut keys displayed at the end of the row. Registering the shortcut is up to the application.
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>).
boolean
default:"true"
ReactElement<unknown, string | JSXElementConstructor<any>>
ReactNode
Icon rendered before the content.
CSSProperties
ReactNode