Collections

Dropdown

A dropdown displays a list of actions or options that a user can choose

Completeness: behavior-required

The stylesheet is only the visible half of this component. It also needs a keyboard map, focus managed across more than one element, ARIA attributes that point at other nodes, and [data-*] attributes that only running code sets — so a CSS-only port will not reproduce it. Use @blakeui/react, or read the interaction contract from the MCP server with get_component_behavior("Dropdown") and build the behaviour yourself.

Import

import { Dropdown } from '@blakeui/react';

Usage

"use client";

import {Button, Dropdown, Label} from "@blakeui/react";

export function Default() {

Anatomy

Import the Dropdown component and access all parts using dot notation.

import { Dropdown, Button, Label, Description, Header, Kbd, Separator } from '@blakeui/react';

export default () => (
  <Dropdown>
    <Dropdown.Trigger>
      <Button />
    </Dropdown.Trigger>
    <Dropdown.Popover>
      <Dropdown.Menu>
        <Dropdown.Item>
          <Label />
          <Description />
          <Kbd slot="keyboard" />
          <Dropdown.ItemIndicator />
        </Dropdown.Item>
        <Separator />
        <Dropdown.Section>
          <Header />
          <Dropdown.Item />
        </Dropdown.Section>
        <Dropdown.SubmenuTrigger>
          <Dropdown.Item>
            <Label />
            <Dropdown.SubmenuIndicator />
          </Dropdown.Item>
          <Dropdown.Popover>
            <Dropdown.Menu>
              <Dropdown.Item />
            </Dropdown.Menu>
          </Dropdown.Popover>
        </Dropdown.SubmenuTrigger>
      </Dropdown.Menu>
    </Dropdown.Popover>
  </Dropdown>
)

With Single Selection

"use client";

import type {Selection} from "@blakeui/react";

import {Button, Dropdown, Header, Label} from "@blakeui/react";

Single With Custom Indicator

"use client";

import type {Selection} from "@blakeui/react";

import {Button, Dropdown, Header, Label} from "@blakeui/react";

With Multiple Selection

"use client";

import type {Selection} from "@blakeui/react";

import {Button, Dropdown, Header, Label} from "@blakeui/react";

With Section Level Selection

"use client";

import type {Selection} from "@blakeui/react";

import {Button, Dropdown, Header, Kbd, Label, Separator} from "@blakeui/react";

With Keyboard Shortcuts

"use client";

import {Button, Dropdown, Kbd, Label} from "@blakeui/react";

export function WithKeyboardShortcuts() {

With Icons

"use client";

import {Button, Dropdown, Kbd, Label} from "@blakeui/react";
import {FloppyDisk, FolderOpen, SquarePlus, TrashBin} from "@gravity-ui/icons";

Long Press Trigger

import {Button, Dropdown, Label} from "@blakeui/react";

export function LongPressTrigger() {
  return (
    <Dropdown trigger="longPress">

With Descriptions

"use client";

import {Button, Description, Dropdown, Kbd, Label} from "@blakeui/react";
import {FloppyDisk, FolderOpen, SquarePlus, TrashBin} from "@gravity-ui/icons";

With Sections

"use client";

import {Button, Description, Dropdown, Header, Kbd, Label, Separator} from "@blakeui/react";
import {EllipsisVertical, Pencil, SquarePlus, TrashBin} from "@gravity-ui/icons";

With Disabled Items

"use client";

import {Button, Description, Dropdown, Header, Kbd, Label, Separator} from "@blakeui/react";
import {Bars, Pencil, SquarePlus, TrashBin} from "@gravity-ui/icons";

With Submenus

"use client";

import {Button, Dropdown, Label} from "@blakeui/react";

export function WithSubmenus() {

With Custom Submenu Indicator

"use client";

import {Button, Dropdown, Label} from "@blakeui/react";
import {ArrowRight} from "@gravity-ui/icons";

Controlled

Selected: bold

"use client";

import type {Selection} from "@blakeui/react";

import {Button, Dropdown, Label} from "@blakeui/react";

Controlled Open State

Dropdown is: closed

"use client";

import {Button, Dropdown, Label} from "@blakeui/react";
import {useState} from "react";

Custom Trigger

import {Avatar, Dropdown, Label} from "@blakeui/react";
import {ArrowRightFromSquare, Gear, Persons} from "@gravity-ui/icons";

export function CustomTrigger() {
  return (

Styling

Passing Tailwind CSS classes

import { Dropdown, Button } from '@blakeui/react';

function CustomDropdown() {
  return (
    <Dropdown>
      <Dropdown.Trigger className="rounded-lg border p-2 bg-surface">
        <Button>Actions</Button>
      </Dropdown.Trigger>
      <Dropdown.Popover className="min-w-[200px]">
        <Dropdown.Menu>
          <Dropdown.Item id="item-1" textValue="Item 1" className="hover:bg-surface-secondary">
            Item 1
          </Dropdown.Item>
        </Dropdown.Menu>
      </Dropdown.Popover>
    </Dropdown>
  );
}

Customizing the component classes

To customize the Dropdown component classes, you can use the @layer components directive.
Learn more.

A worked example is in Styling.

blakeUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

The Dropdown component uses these CSS classes (View source styles):

Base Classes

  • .dropdown - Base dropdown container
  • .dropdown__trigger - The button or element that triggers the dropdown
  • .dropdown__popover - The popover container
  • .dropdown__menu - The menu container inside the popover

State Classes

  • .dropdown__trigger[data-focus-visible="true"] - Focused trigger state
  • .dropdown__trigger[data-disabled="true"] - Disabled trigger state
  • .dropdown__trigger[data-pressed="true"] - Pressed trigger state
  • .dropdown__popover[data-entering] - Entering animation state
  • .dropdown__popover[data-exiting] - Exiting animation state
  • .dropdown__menu[data-selection-mode="single"] - Single selection mode
  • .dropdown__menu[data-selection-mode="multiple"] - Multiple selection mode

The Dropdown component uses Menu, MenuItem, and MenuSection as base components. These classes are also available for customization:

  • .menu - Base menu container (menu.css)
    • [data-slot="separator"] - Separator elements within the menu
  • .menu-item - Base menu item container (menu-item.css)
  • .menu-item__indicator - Selection indicator (checkmark or dot)
    • [data-slot="menu-item-indicator--checkmark"] - Checkmark indicator SVG
    • [data-slot="menu-item-indicator--dot"] - Dot indicator SVG
  • .menu-item__indicator--submenu - Submenu indicator (chevron)
  • .menu-item--default - Default variant styling
  • .menu-item--danger - Danger variant styling
  • .menu-item[data-focus-visible="true"] - Focused item state (keyboard focus)
  • .menu-item[data-focus="true"] - Focused item state
  • .menu-item[data-pressed] - Pressed item state
  • .menu-item[data-hovered] - Hovered item state
  • .menu-item[data-selected="true"] - Selected item state
  • .menu-item[data-disabled] - Disabled item state
  • .menu-item[data-has-submenu="true"] - Item with submenu
  • .menu-item[data-selection-mode="single"] - Single selection mode
  • .menu-item[data-selection-mode="multiple"] - Multiple selection mode
  • .menu-item[aria-checked="true"] - Checked item (ARIA)
  • .menu-item[aria-selected="true"] - Selected item (ARIA)

Interactive States

The component supports both CSS pseudo-classes and data attributes for flexibility:

  • Hover: :hover or [data-hovered="true"] on trigger and items
  • Focus: :focus-visible or [data-focus-visible="true"] on trigger and items
  • Disabled: :disabled or [data-disabled="true"] on trigger and items
  • Pressed: :active or [data-pressed="true"] on trigger and items
  • Selected: [data-selected="true"] or [aria-selected="true"] on items

API Reference

PropTypeDefaultDescription
isOpenboolean-Sets the open state of the menu (controlled)
defaultOpenboolean-Sets the default open state of the menu (uncontrolled)
onOpenChange(isOpen: boolean) => void-Handler called when the open state changes
trigger"press" | "longPress""press"The type of interaction that triggers the menu
classNamestring-Additional CSS classes
childrenReactNode-Dropdown content
PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReactNode | RenderFunction-Trigger content or render function

All Button props are also supported when using a Button as the trigger.

PropTypeDefaultDescription
placement"bottom" | "bottom left" | "bottom right" | "bottom start" | "bottom end" | "top" | "top left" | "top right" | "top start" | "top end" | "left" | "left top" | "left bottom" | "start" | "start top" | "start bottom" | "right" | "right top" | "right bottom" | "end" | "end top" | "end bottom""bottom"Placement of the popover relative to the trigger
classNamestring-Additional CSS classes
childrenReactNode-Content children

All Popover props are also supported.

PropTypeDefaultDescription
selectionMode"single" | "multiple" | "none""none"Whether single or multiple selection is enabled
selectedKeysIterable<Key>-The currently selected keys (controlled)
defaultSelectedKeysIterable<Key>-The initial selected keys (uncontrolled)
onSelectionChange(keys: Selection) => void-Handler called when the selection changes
disabledKeysIterable<Key>-Keys of disabled items
onAction(key: Key) => void-Handler called when an item is activated
classNamestring-Additional CSS classes
childrenReactNode-Menu content

All Menu props are also supported.

PropTypeDefaultDescription
selectionMode"single" | "multiple"-Selection mode for items within this section
selectedKeysIterable<Key>-The currently selected keys (controlled)
defaultSelectedKeysIterable<Key>-The initial selected keys (uncontrolled)
onSelectionChange(keys: Selection) => void-Handler called when the selection changes
disabledKeysIterable<Key>-Keys of disabled items
classNamestring-Additional CSS classes
childrenReactNode-Section content

All MenuSection props are also supported.

PropTypeDefaultDescription
idKey-Unique identifier for the item
textValuestring-Text content of the item for typeahead
variant"default" | "danger""default"Visual variant of the item
classNamestring-Additional CSS classes
childrenReactNode | RenderFunction-Item content or render function

All MenuItem props are also supported.

PropTypeDefaultDescription
type"checkmark" | "dot""checkmark"Type of indicator to display
classNamestring-Additional CSS classes
childrenReactNode | RenderFunction-Custom indicator content or render function

When using a render function, these values are provided:

PropTypeDescription
isSelectedbooleanWhether the item is selected
isIndeterminatebooleanWhether the item is in an indeterminate state
PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReactNode-Custom indicator content
PropTypeDefaultDescription
classNamestring-Additional CSS classes
childrenReactNode-Submenu trigger content

All SubmenuTrigger props are also supported.

RenderProps

When using render functions with Dropdown.Item, these values are provided:

PropTypeDescription
isSelectedbooleanWhether the item is selected
isFocusedbooleanWhether the item is focused
isDisabledbooleanWhether the item is disabled
isPressedbooleanWhether the item is being pressed

Examples

Basic Usage

import { Dropdown, Button, Label } from '@blakeui/react';

<Dropdown>
  <Button aria-label="Menu" variant="secondary">
    Actions
  </Button>
  <Dropdown.Popover>
    <Dropdown.Menu onAction={(key) => alert(`Selected: ${key}`)}>
      <Dropdown.Item id="new-file" textValue="New file">
        <Label>New file</Label>
      </Dropdown.Item>
      <Dropdown.Item id="open-file" textValue="Open file">
        <Label>Open file</Label>
      </Dropdown.Item>
      <Dropdown.Item id="delete-file" textValue="Delete file" variant="danger">
        <Label>Delete file</Label>
      </Dropdown.Item>
    </Dropdown.Menu>
  </Dropdown.Popover>
</Dropdown>

With Sections

import { Dropdown, Button, Label, Header, Separator } from '@blakeui/react';

<Dropdown>
  <Button aria-label="Menu" variant="secondary">
    Actions
  </Button>
  <Dropdown.Popover>
    <Dropdown.Menu onAction={(key) => alert(`Selected: ${key}`)}>
      <Dropdown.Section>
        <Header>Actions</Header>
        <Dropdown.Item id="new-file" textValue="New file">
          <Label>New file</Label>
        </Dropdown.Item>
        <Dropdown.Item id="edit-file" textValue="Edit file">
          <Label>Edit file</Label>
        </Dropdown.Item>
      </Dropdown.Section>
      <Separator />
      <Dropdown.Section>
        <Header>Danger zone</Header>
        <Dropdown.Item id="delete-file" textValue="Delete file" variant="danger">
          <Label>Delete file</Label>
        </Dropdown.Item>
      </Dropdown.Section>
    </Dropdown.Menu>
  </Dropdown.Popover>
</Dropdown>

Controlled Selection

import type { Selection } from '@blakeui/react';

import { Dropdown, Button, Label } from '@blakeui/react';
import { useState } from 'react';

function ControlledDropdown() {
  const [selected, setSelected] = useState<Selection>(new Set(['bold']));

  return (
    <Dropdown>
      <Button aria-label="Menu" variant="secondary">
        Actions
      </Button>
      <Dropdown.Popover>
        <Dropdown.Menu
          selectedKeys={selected}
          selectionMode="multiple"
          onSelectionChange={setSelected}
        >
          <Dropdown.Item id="bold" textValue="Bold">
            <Label>Bold</Label>
            <Dropdown.ItemIndicator />
          </Dropdown.Item>
          <Dropdown.Item id="italic" textValue="Italic">
            <Label>Italic</Label>
            <Dropdown.ItemIndicator />
          </Dropdown.Item>
        </Dropdown.Menu>
      </Dropdown.Popover>
    </Dropdown>
  );
}

With Submenus

import { Dropdown, Button, Label } from '@blakeui/react';

<Dropdown>
  <Button aria-label="Menu" variant="secondary">
    Share
  </Button>
  <Dropdown.Popover>
    <Dropdown.Menu onAction={(key) => alert(`Selected: ${key}`)}>
      <Dropdown.Item id="copy-link" textValue="Copy Link">
        <Label>Copy Link</Label>
      </Dropdown.Item>
      <Dropdown.SubmenuTrigger>
        <Dropdown.Item id="share" textValue="Share">
          <Label>Other</Label>
          <Dropdown.SubmenuIndicator />
        </Dropdown.Item>
        <Dropdown.Popover>
          <Dropdown.Menu>
            <Dropdown.Item id="whatsapp" textValue="WhatsApp">
              <Label>WhatsApp</Label>
            </Dropdown.Item>
            <Dropdown.Item id="telegram" textValue="Telegram">
              <Label>Telegram</Label>
            </Dropdown.Item>
          </Dropdown.Menu>
        </Dropdown.Popover>
      </Dropdown.SubmenuTrigger>
    </Dropdown.Menu>
  </Dropdown.Popover>
</Dropdown>

Accessibility

The Dropdown component implements the ARIA menu pattern and provides:

  • Full keyboard navigation support (arrow keys, home/end, typeahead)
  • Screen reader announcements for actions and selection changes
  • Proper focus management
  • Support for disabled states
  • Long press interaction support
  • Submenu navigation

For more information, see the React Aria Menu documentation.

On this page