Menu component built on Base UI, styled with sc1m tokens.
Stable Base UI
pnpm dlx shadcn@latest add @sc1m/menu
This also merges the token layer and installs
src/lib/cn.ts plus @base-ui/react. For the manual route — prerequisites,
components.json, and app-level setup — see Installation .
import {
Menu,
MenuTrigger,
MenuContent,
MenuItem,
MenuCheckboxItem,
MenuCheckboxItemIndicator,
MenuRadioGroup,
MenuRadioItem,
MenuRadioItemIndicator,
MenuSeparator,
MenuGroup,
MenuGroupLabel,
MenuSubmenuRoot,
MenuSubmenuTrigger,
} from "@/components/ui/menu" ;
Every part is a separate export. Menu owns state; the rest are
presentational and must appear in this order.
Menu ├── MenuTrigger └── MenuContent ├── MenuItem └── MenuSeparator
The preview above, with its source. This is the demo module verbatim, so
the code and the thing it renders cannot drift apart.
Each part forwards every prop of its Base UI counterpart; the tables list
the ones declared on the part itself. See
Base UI's reference
for the inherited element props.
Prop Type Default Description
defaultOpen boolean false Whether the menu is initially open.
loopFocus boolean true Whether to loop keyboard focus back to the first item when the end of the list is reached while using the arrow keys.
highlightItemOnHover boolean true Whether moving the pointer over items should highlight them.
modal boolean true Determines if the menu enters a modal state when open.
onOpenChange ((open: boolean, eventDetails: MenuRoot.ChangeEventDetails) => void) — Event handler called when the menu is opened or closed.
onOpenChangeComplete ((open: boolean) => void) — Event handler called after any animations complete when the menu is opened or closed.
open boolean — Whether the menu is currently open.
orientation MenuRoot.Orientation 'vertical' The visual orientation of the menu.
disabled boolean false Whether the component should ignore user interaction.
closeParentOnEsc boolean false When in a submenu, determines whether pressing the Escape key closes the entire menu, or only the current child menu.
actionsRef React.RefObject<MenuRoot.Actions | null> — A ref to imperative actions.
triggerId string | null — ID of the trigger that the menu is associated with.
defaultTriggerId string | null — ID of the trigger that the menu is associated with.
handle MenuHandle<Payload> — A handle to associate the menu with a trigger.
Prop Type Default Description
disabled boolean false Whether the component should ignore user interaction.
handle MenuHandle<Payload> — A handle to associate the trigger with a menu.
payload Payload — A payload to pass to the menu when it is opened.
delay number 100 How long to wait before the menu may be opened on hover.
closeDelay number 0 How long to wait before closing the menu that was opened on hover.
openOnHover boolean — Whether the menu should also open when the trigger is hovered.
Prop Type Default Description
id string —
finalFocus boolean | React.RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | HTMLElement | null | void) — Determines the element to focus when the menu is closed.
Prop Type Default Description
onClick BaseUIComponentProps<'div', MenuItemState>['onClick'] — The click handler for the menu item.
disabled boolean false Whether the component should ignore user interaction.
label string — Overrides the text label to use when the item is matched during keyboard text navigation.
id string —
closeOnClick boolean true Whether to close the menu when the item is clicked.
Prop Type Default Description
checked boolean — Whether the checkbox item is currently ticked.
defaultChecked boolean false Whether the checkbox item is initially ticked.
onCheckedChange ((checked: boolean, eventDetails: MenuCheckboxItem.ChangeEventDetails) => void) — Event handler called when the checkbox item is ticked or unticked.
onClick BaseUIComponentProps<'div', MenuCheckboxItemState>['onClick'] — The click handler for the menu item.
disabled boolean false Whether the component should ignore user interaction.
label string — Overrides the text label to use when the item is matched during keyboard text navigation.
id string —
closeOnClick boolean false Whether to close the menu when the item is clicked.
Prop Type Default Description
keepMounted boolean false Whether to keep the HTML element in the DOM when the checkbox item is not checked.
Prop Type Default Description
value any — The controlled value of the radio item that should be currently selected.
defaultValue any — The uncontrolled value of the radio item that should be initially selected.
onValueChange ((value: any, eventDetails: MenuRadioGroup.ChangeEventDetails) => void) — Function called when the selected value changes.
disabled boolean false Whether the component should ignore user interaction.
Prop Type Default Description
value any — Value of the radio item.
onClick BaseUIComponentProps<'div', MenuRadioItemState>['onClick'] — The click handler for the menu item.
disabled boolean false Whether the component should ignore user interaction.
label string — Overrides the text label to use when the item is matched during keyboard text navigation.
id string —
closeOnClick boolean false Whether to close the menu when the item is clicked.
Prop Type Default Description
keepMounted boolean false Whether to keep the HTML element in the DOM when the radio item is inactive.
Prop Type Default Description
onOpenChange ((open: boolean, eventDetails: MenuSubmenuRoot.ChangeEventDetails) => void) — Event handler called when the menu is opened or closed.
closeParentOnEsc boolean false When in a submenu, determines whether pressing the Escape key closes the entire menu, or only the current child menu.
Prop Type Default Description
onClick BaseUIComponentProps<'div', MenuSubmenuTriggerState>['onClick'] —
label string — Overrides the text label to use when the item is matched during keyboard text navigation.
id string —
disabled boolean false Whether the component should ignore user interaction.
delay number 100 How long to wait before the menu may be opened on hover.
closeDelay number 0 How long to wait before closing the menu that was opened on hover.
openOnHover boolean — Whether the menu should also open when the trigger is hovered.
Behaviour, focus management, and ARIA wiring come from Base UI's Menu — see its reference for the full keyboard map.
Decorative glyphs are aria-hidden, so they are not announced.
Disabled parts mute their contents rather than the element, keeping the focus ring at full strength where the part stays focusable.
The component reads semantic tokens only — no raw colour, radius, or
duration appears in its source. Override the token, not the component.
Token Applied to
--brand-radius-lg MenuContent
--brand-radius-sm MenuItem, MenuCheckboxItem, MenuRadioItem, MenuSubmenuTrigger
--fg MenuContent, MenuRadioItemIndicator
--fg-subtle MenuGroupLabel, MenuSubmenuTrigger
--line MenuContent, MenuSeparator
--shadow-overlay MenuContent
--surface MenuItem, MenuCheckboxItem, MenuRadioItem, MenuSubmenuTrigger
--surface-raised MenuContent
src/components/ui/menu/menu.tsx — no next/* imports, so it drops into any
React 19 + Tailwind v4 app.