Overlays

Menu

Dropdown actions with icons, platform-aware shortcuts, checkbox/radio items, submenus and a calm destructive variant. The highlight is a quiet tint, not the accent.

Live example

Import

Each family is its own entry point, so a page loads only what it uses.

tsx
import { Button, IconButton } from "@nibapp/ui/components/button";import { Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuGroupLabel, MenuItem, MenuRadioGroup, MenuRadioItem, MenuRoot, MenuSeparator, MenuSubmenuContent, MenuSubmenuRoot, MenuSubmenuTrigger, MenuTrigger } from "@nibapp/ui/components/menu";

Props

Each component's own props and variants, read from its source. What it also takes from an element or a Base UI part is named below its table.

Button

PropTypeDefaultDescription
variant"primary" | "secondary" | "ghost" | "quiet" | "danger" | "danger-ghost" | "link""secondary"
primary
Neutral ink: the main call to action. Actions are ink, never the accent.
secondary
Quiet surface with a hairline — the default for most actions.
ghost
No chrome until hovered — toolbars, inline actions.
quiet
Words that are also an action, in the text's own weight and laid out from the start, so they line up with the text around them: `xs` in a line (a header's crumbs, a title that renames), `sm` a toolbar's picker, `md` a row in a list or a popover ("Open settings", a sidebar's link).
danger
Destructive confirmation.
danger-ghost
Destructive but low emphasis.
link
Inline text action.
size"xs" | "sm" | "md" | "lg""md"
blockboolean—
truncateboolean—

The button may shrink below its label's width; the label then truncates with an ellipsis.

wrapboolean—

The label wraps onto more lines and the button grows, its `leading` icon on the first line: for words that are an action and may run long in another language (a tip). One line keeps the size.

loadingbooleanfalse

Shows a spinner, keeps the button's width, and blocks interaction.

leadingReactNode—

Icon rendered before the label.

trailingReactNode—

Icon or hint (e.g. <Kbd>) rendered after the label.

disabledReasonstring | undefined—

Disables the button and says why: the reason is its tooltip and its accessible description, and the button stays focusable (`aria-disabled`) so a keyboard reaches it.

Also takes .

IconButton

Square, icon-only button. Pair with <Tooltip> to surface the label visually (a `disabledReason` brings its own).

PropTypeDefaultDescription
size"xs" | "sm" | "md" | "lg""md"
aria-label (required)string—

Required: icon-only controls must be named for assistive tech.

children (required)ReactNode—
loadingbooleanfalse
disabledReasonstring | undefined—

Disables the button and says why, as Button's `disabledReason`.

Also takes the props of Base UI's Button, except aria-label and children.

Menu

Convenience wrapper: `<Menu trigger={<Button>Options</Button>}>…items…</Menu>`.

PropTypeDefaultDescription
trigger (required)ComponentProps<typeof BaseMenu.Trigger>["render"]—

The trigger element; must accept a ref and DOM props (e.g. <Button>).

children (required)ReactNode—
sideMenuContentProps["side"]—
alignMenuContentProps["align"]—
openboolean—
onOpenChangeComponentProps<typeof BaseMenu.Root>["onOpenChange"]—
classNamestring—

Popup class (e.g. a width).

containerMenuContentProps["container"]—

Where the popup mounts (`MenuContent`'s `container`).

positionerPropsMenuContentProps["positionerProps"]—

Positioner props (`MenuContent`'s `positionerProps`).

MenuCheckboxItem

Toggle with a leading check. Stays open on click so several options can be flipped.

PropTypeDefaultDescription
childrenReactNode—

Also takes the props of Base UI's Menu.CheckboxItem, except children, and ItemSlots, except icon.

MenuContent

Portal + positioner + popup in one.

PropTypeDefaultDescription
sideComponentProps<typeof BaseMenu.Positioner>["side"]"bottom"
alignComponentProps<typeof BaseMenu.Positioner>["align"]"start"
sideOffsetnumber6
alignOffsetnumber0
positionerPropsOmit< ComponentProps<typeof BaseMenu.Positioner>, "side" | "align" | "sideOffset" | "alignOffset" >—

Extra props for the positioner (collision handling, anchor…).

containerComponentProps<typeof BaseMenu.Portal>["container"]—

Where the popup mounts (default: the body). Inside a container-query container, its items can follow that container's width, e.g. an overflow menu showing what its bar hides.

Also takes .

MenuGroupLabel

Also takes the props of Base UI's Menu.GroupLabel.

MenuItem

PropTypeDefaultDescription
variant"default" | "destructive""default"
destructive
Irreversible or data-losing actions. Tinted only on highlight so menus stay calm.
insetboolean—

Reserve the leading indicator column so plain items align with checkbox/radio items.

childrenReactNode—

Also takes the props of Base UI's Menu.Item, except children, and .

MenuRadioItem

One choice of a `MenuRadioGroup`. The check sits on the trailing edge when an `icon` is given (model pickers), otherwise in the leading indicator column.

PropTypeDefaultDescription
childrenReactNode—

Also takes the props of Base UI's Menu.RadioItem, except children, and .

MenuSeparator

Also takes the props of Base UI's Menu.Separator.

MenuSubmenuContent

Popup for a nested menu. Overlaps the parent by its padding so the first item lines up with the trigger row.

Also takes MenuContentProps, except side and align.

MenuSubmenuTrigger

PropTypeDefaultDescription
childrenReactNode—

Also takes the props of Base UI's Menu.SubmenuTrigger, except children, and , and .