Skip to content
Browse documentation
DocsComponents

Menu

Contextual actions anchored to an icon button.

More actions

Installation

Terminal
pnpm dlx shadcn@latest add https://react-toolbox.io/r/menu.json

New here? Set up your project first. Styles, fonts, and required components are included.

Usage

IconMenu handles opening, keyboard navigation, and dismissal. Use onSelect to respond to an item value. Menu and MenuDivider are also available for custom compositions.

Use the Code tab above for a complete example. The import follows your configured UI alias. See Theming to customize colors, spacing, and style slots.

State and callbacks

Menu visibility and selected value are controlled through active and selected. Update selected from onSelect; use onHide to close a controlled popup. Selection and visibility are separate.

IconMenu manages trigger opening and dismissal internally and synchronizes changes to active. Its selected value remains controlled. The ref exposes open(), close(), and node for imperative integration.

API reference

Generated from the installed TypeScript source. Defaults are the values declared by each function; a dash means no parameter default is declared. Forwarded props can use the receiving component’s default. Callback types show the exact arguments passed to your handler.

Menu

PropertyTypeDefault
activebooleanfalse
initialFocus'first' | 'last''first'
outlinebooleantrue
positionMenuPosition'static'
ripplebooleantrue
selectablebooleantrue
selectedValue—
classNamesMenuTheme

Classes for the component's rendered parts. Applied after legacy theme overrides.

—
themeDeprecated aliasMenuTheme

Use classNames for style slots; use ThemeProvider for design tokens.

—
refRef<MenuHandle>—

Callbacks

PropertyTypeDefault
onHide() => void—
onSelect(value: Value | undefined) => void—
onShow() => void—
onKeyDown(event: KeyboardEvent<HTMLUListElement>) => void—

Also inherits Omit<HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onKeyDown'>, except the omissions and overrides in its exported props type below. Use the supported native aria-*, data-*, event, and element attributes as appropriate.

Style slots

Pass a map of Tailwind classes to classNames. Available keys:

  • active
  • bottomLeft
  • bottomRight
  • caption
  • disabled
  • icon
  • iconMenu
  • menu
  • menuDivider
  • menuInner
  • menuItem
  • outline
  • ripple
  • rippled
  • selected
  • shortcut
  • static
  • topLeft
  • topRight

theme is the deprecated compatibility alias. When both are provided, classNames wins conflicting utilities within each slot. See Theming for tokens and override rules.

MenuItem

PropertyTypeDefault
captionReactNode—
disabledbooleanfalse
iconReactNode—
selectedbooleanfalse
shortcutReactNode—
valueValue—
ripplebooleantrue
classNamesMenuItemTheme

Classes for the component's rendered parts. Applied after legacy theme overrides.

—
themeDeprecated aliasMenuItemTheme

Use classNames for style slots; use ThemeProvider for design tokens.

—
refRef<MenuItemHandle<Value>>—

Callbacks

PropertyTypeDefault
onClick(event: MouseEvent<HTMLLIElement> | KeyboardEvent<HTMLLIElement>, item: MenuItemHandle<Value>) => void—

Also inherits Omit<HTMLAttributes<HTMLLIElement>, 'onClick'>, except the omissions and overrides in its exported props type below. Use the supported native aria-*, data-*, event, and element attributes as appropriate.

Style slots

Pass a map of Tailwind classes to classNames. Available keys:

  • active
  • bottomLeft
  • bottomRight
  • caption
  • disabled
  • icon
  • iconMenu
  • menu
  • menuDivider
  • menuInner
  • menuItem
  • outline
  • ripple
  • rippled
  • selected
  • shortcut
  • static
  • topLeft
  • topRight

theme is the deprecated compatibility alias. When both are provided, classNames wins conflicting utilities within each slot. See Theming for tokens and override rules.

MenuDivider

PropertyTypeDefault
classNamesMenuDividerTheme

Classes for the component's rendered parts. Applied after legacy theme overrides.

—
themeDeprecated aliasMenuDividerTheme

Use classNames for style slots; use ThemeProvider for design tokens.

—
refRef<HTMLHRElement>—

Also inherits HTMLAttributes<HTMLHRElement>, except the omissions and overrides in its exported props type below. Use the supported native aria-*, data-*, event, and element attributes as appropriate.

Style slots

Pass a map of Tailwind classes to classNames. Available keys:

  • active
  • bottomLeft
  • bottomRight
  • caption
  • disabled
  • icon
  • iconMenu
  • menu
  • menuDivider
  • menuInner
  • menuItem
  • outline
  • ripple
  • rippled
  • selected
  • shortcut
  • static
  • topLeft
  • topRight

theme is the deprecated compatibility alias. When both are provided, classNames wins conflicting utilities within each slot. See Theming for tokens and override rules.

IconMenu

PropertyTypeDefault
activebooleanfalse
iconReactNode'more_vert'
iconRipplebooleantrue
inverseboolean—
menuRipplebooleantrue
positionMenuPosition'auto'
selectablebooleanfalse
selectedValue—
classNamesIconMenuTheme

Classes for the component's rendered parts. Applied after legacy theme overrides.

—
themeDeprecated aliasIconMenuTheme

Use classNames for style slots; use ThemeProvider for design tokens.

—
refRef<IconMenuHandle>—

Callbacks

PropertyTypeDefault
onClickReact.MouseEventHandler<HTMLElement>—
onHide() => void—
onSelect(value: Value | undefined) => void—
onShow() => void—

Also inherits Omit<HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onClick'>, except the omissions and overrides in its exported props type below. Use the supported native aria-*, data-*, event, and element attributes as appropriate.

Style slots

Pass a map of Tailwind classes to classNames. Available keys:

  • active
  • bottomLeft
  • bottomRight
  • caption
  • disabled
  • icon
  • iconMenu
  • menu
  • menuDivider
  • menuInner
  • menuItem
  • outline
  • ripple
  • rippled
  • selected
  • shortcut
  • static
  • topLeft
  • topRight

theme is the deprecated compatibility alias. When both are provided, classNames wins conflicting utilities within each slot. See Theming for tokens and override rules.

Exported TypeScript types

Expand a type to inspect its full declaration, including generic constraints, union branches, callback arguments, ref handles, and inherited props. Import these types from @/components/ui/material/menu.

MenuTheme
tsx
type MenuTheme = Partial<
  Record<
    | 'active'
    | 'bottomLeft'
    | 'bottomRight'
    | 'caption'
    | 'disabled'
    | 'icon'
    | 'iconMenu'
    | 'menu'
    | 'menuDivider'
    | 'menuInner'
    | 'menuItem'
    | 'outline'
    | 'ripple'
    | 'rippled'
    | 'selected'
    | 'shortcut'
    | 'static'
    | 'topLeft'
    | 'topRight',
    string
  >
>;
MenuClassNames
tsx
type MenuClassNames = MenuTheme;
MenuPosition
tsx
type MenuPosition = 'auto' | 'static' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
MenuHandle
tsx
interface MenuHandle {
  show(): void;
  hide(): void;
  readonly node: HTMLDivElement | null;
}
MenuProps
tsx
interface MenuProps<Value = unknown> extends Omit<HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onKeyDown'> {
  active?: boolean;
  initialFocus?: 'first' | 'last';
  onHide?: () => void;
  onSelect?: (value: Value | undefined) => void;
  onShow?: () => void;
  onKeyDown?: (event: KeyboardEvent<HTMLUListElement>) => void;
  outline?: boolean;
  position?: MenuPosition;
  ripple?: boolean;
  selectable?: boolean;
  selected?: Value;
  /** Classes for the component's rendered parts. Applied after legacy theme overrides. */
  classNames?: MenuTheme;
  /** @deprecated Use classNames for style slots; use ThemeProvider for design tokens. */
  theme?: MenuTheme;
  ref?: Ref<MenuHandle>;
}
MenuItemTheme
tsx
type MenuItemTheme = MenuTheme;
MenuItemEvent
tsx
type MenuItemEvent = MouseEvent<HTMLLIElement> | KeyboardEvent<HTMLLIElement>;
MenuItemHandle
tsx
interface MenuItemHandle<Value = unknown> {
  readonly node: HTMLLIElement | null;
  readonly value: Value | undefined;
}
MenuItemProps
tsx
interface MenuItemProps<Value = unknown> extends Omit<HTMLAttributes<HTMLLIElement>, 'onClick'> {
  caption?: ReactNode;
  disabled?: boolean;
  icon?: ReactNode;
  selected?: boolean;
  shortcut?: ReactNode;
  value?: Value;
  ripple?: boolean;
  onClick?: (event: MenuItemEvent, item: MenuItemHandle<Value>) => void;
  /** Classes for the component's rendered parts. Applied after legacy theme overrides. */
  classNames?: MenuItemTheme;
  /** @deprecated Use classNames for style slots; use ThemeProvider for design tokens. */
  theme?: MenuItemTheme;
  ref?: Ref<MenuItemHandle<Value>>;
}
MenuItemClassNames
tsx
type MenuItemClassNames = MenuItemTheme;
MenuDividerTheme
tsx
type MenuDividerTheme = MenuTheme;
MenuDividerProps
tsx
interface MenuDividerProps extends HTMLAttributes<HTMLHRElement> {
  /** Classes for the component's rendered parts. Applied after legacy theme overrides. */
  classNames?: MenuDividerTheme;
  /** @deprecated Use classNames for style slots; use ThemeProvider for design tokens. */
  theme?: MenuDividerTheme;
  ref?: Ref<HTMLHRElement>;
}
MenuDividerClassNames
tsx
type MenuDividerClassNames = MenuDividerTheme;
IconMenuTheme
tsx
type IconMenuTheme = MenuTheme;
IconMenuHandle
tsx
interface IconMenuHandle {
  open(): void;
  close(): void;
  readonly node: HTMLDivElement | null;
}
IconMenuProps
tsx
interface IconMenuProps<Value = unknown> extends Omit<HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onClick'> {
  active?: boolean;
  icon?: ReactNode;
  iconRipple?: boolean;
  inverse?: boolean;
  menuRipple?: boolean;
  onClick?: React.MouseEventHandler<HTMLElement>;
  onHide?: () => void;
  onSelect?: MenuProps<Value>['onSelect'];
  onShow?: () => void;
  position?: MenuPosition;
  selectable?: boolean;
  selected?: Value;
  /** Classes for the component's rendered parts. Applied after legacy theme overrides. */
  classNames?: IconMenuTheme;
  /** @deprecated Use classNames for style slots; use ThemeProvider for design tokens. */
  theme?: IconMenuTheme;
  ref?: Ref<IconMenuHandle>;
}
IconMenuClassNames
tsx
type IconMenuClassNames = IconMenuTheme;

Material guidelines

  • Menus present brief contextual choices near their trigger. Use a navigation drawer or other persistent navigation pattern for top-level destinations.
  • Use short, single-line labels and dismiss the menu after a single selection. If choices need wrapping or extensive explanation, use a dialog.

Material Design 1: Menus