Code

Menu is installed into your project as a file you own. It takes the same props as Ant Design v6's Menu and adds no prop or variant: mode sets the shape and theme sets how loud it is. The one change is the horizontal overflow icon, which comes from your icon pack. That row and the ref are marked antuikit in the API table below. Menu.Item, Menu.SubMenu, Menu.Divider and Menu.ItemGroup are still exported, to help you migrate a menu written as children to items.

Install

npx antuikit@latest init
npx antuikit@latest add menu
The first command installs AntuikitProvider and the theme tokens, the second adds this component and Icon.

Import

From @/components/ui/menu, never from antd. The file lives in your project, so the import is a path, not a package.
import { Menu } from "@/components/ui/menu"

The axes

Two props take a fixed set of values. The Design tab's Figma properties follow the same two.
  • mode takes inline, vertical and horizontal, and defaults to vertical. It decides where a submenu goes: expanded in place under its parent (inline), opened as a popup to the side (vertical), or opened below a row that also collects the items that do not fit (horizontal).
  • theme takes light (the default) and dark. It sets how loud the menu is, whatever the page's light or dark mode, so a dark sidebar on a light page works as expected. A submenu entry takes its own theme too, for a popup that differs from the rest.
  • direction cannot be set on one menu. A value passed here is overwritten by the provider's, so set it on ConfigProvider, where it also flips which arrow key moves into a submenu.

Flags

Each turns one behavior on or off. Only selectable defaults to true.
  • selectable defaults to true. Setting it false turns the menu into an actions list: onClick still fires and nothing stays highlighted.
  • multiple lets more than one key stay selected at once. It is off by default, and it is the flag that makes onDeselect reachable at all.
  • inlineCollapsed shrinks an inline menu to its icons. It only works with mode="inline". Leave it unset inside a Layout.Sider: the Sider collapses the menu for you, and setting both stops the menu following the Sider.
  • disabled disables every item at once, which also takes the whole menu out of arrow-key reach. Prefer leaving items enabled and explaining at the destination.
  • disabledOverflow keeps every item in the row, so nothing moves into the trailing submenu. It only applies to mode="horizontal".
  • forceSubMenuRender mounts every submenu on first paint instead of on first open. Use it when something inside a closed submenu has to exist, like a form field that must submit.

Slots

The props that take a node. A submenu popup renders in a portal, so a selector written on the root does not reach what you put there.
  • overflowedIndicator is the title of the trailing submenu that holds the items a horizontal menu has no room for. The kit fills it with your icon pack's more icon. Pass your own node to replace it, or null for none. Put a word in what you pass, because an icon alone has no name for a screen reader.
  • expandIcon replaces the submenu arrow. The default arrow is drawn with CSS, not an icon, so it stays the same when you change the icon pack. Pass an Icon here if you want one.
  • itemIcon renders after every item's content, for a trailing marker. The leading icon is the icon key on each items entry. Pass an <Icon> there so it follows the icon pack.
  • popupRender wraps or replaces a submenu's popup, for a mega menu or any panel that is more than a list.
  • getPopupContainer decides where that portal is mounted. Point it at a scrolling ancestor so an open popup travels with the menu instead of staying put.

Events

  • onSelect
  • onDeselect
  • onClick
  • onOpenChange

Styling

className and style land on the root. To style one part, pass classNames or styles keyed by root, list, item, itemTitle, itemIcon and itemContent. popup and subMenu reach the submenu popups, which a selector on the root cannot.

API Reference