Menu
A dropdown menu built on Base UI’s Menu primitive. Supports plain items, groups, checkbox items, and radio groups. Animates with Motion when available, falls back to CSS transitions.
Import
import { Menu } from "chunks-ui";Basic Usage
<Menu.Root>
<Menu.Trigger>Options</Menu.Trigger>
<Menu.Content>
<Menu.Item>View profile</Menu.Item>
<Menu.Item>Edit settings</Menu.Item>
<Menu.Separator />
<Menu.Item>Sign out</Menu.Item>
</Menu.Content>
</Menu.Root>Groups
Use Menu.Group with Menu.GroupLabel to organize items into labelled sections:
<Menu.Root>
<Menu.Trigger>Actions</Menu.Trigger>
<Menu.Content>
<Menu.Group>
<Menu.GroupLabel>File</Menu.GroupLabel>
<Menu.Item>New file</Menu.Item>
<Menu.Item>Open...</Menu.Item>
</Menu.Group>
<Menu.Separator />
<Menu.Group>
<Menu.GroupLabel>Edit</Menu.GroupLabel>
<Menu.Item>Undo</Menu.Item>
<Menu.Item>Redo</Menu.Item>
</Menu.Group>
</Menu.Content>
</Menu.Root>Checkbox Items
Menu.CheckboxItem keeps a checked state. Pair with Menu.CheckboxItemIndicator to show a check mark:
<Menu.CheckboxItem checked={showGrid} onCheckedChange={setShowGrid}>
<Menu.CheckboxItemIndicator>✓</Menu.CheckboxItemIndicator>
Show grid
</Menu.CheckboxItem>Radio Group
Menu.RadioGroup enforces single selection among Menu.RadioItem children:
<Menu.RadioGroup value={theme} onValueChange={setTheme}>
<Menu.RadioItem value="light">
<Menu.RadioItemIndicator>•</Menu.RadioItemIndicator>
Light
</Menu.RadioItem>
<Menu.RadioItem value="dark">
<Menu.RadioItemIndicator>•</Menu.RadioItemIndicator>
Dark
</Menu.RadioItem>
</Menu.RadioGroup>Positioning
Menu.Content accepts positioning props forwarded to Base UI’s positioner:
<Menu.Content side="right" align="start" sideOffset={12}>
...
</Menu.Content>Animation
The popup enters with a scale-up and fade (from scale-95 and opacity-0): the popup spring (springs.popup) with Motion installed, a CSS transition of opacity and scale without it; reduced motion turns off both. The popup grows out of its trigger (origin-(--transform-origin)); a className such as origin-top replaces it.
render on Menu.Content replaces the element the spring animates, so a popup with render uses the CSS transition even with Motion installed. To restyle the popup, pass className.
Compound Parts
| Part | Description |
|---|---|
Menu.Root | State container. Manages open/close. |
Menu.Trigger | Element that opens the menu. |
Menu.Content | Portal + positioner + popup panel. Default sideOffset={8}, as on Popover.Content: the popup’s focus ring, 4px outside its edge, stays clear of the trigger. Scrolls when the items need more than the space between the trigger and the viewport edge. The items scroll in an inner element, so layout classes on Menu.Content (such as grid or gap-*) do not reach them: wrap the items in your own element instead. When the menu itself takes focus, as when a shortcut opens it, it shows the library focus ring after keyboard use: 2px of --ring, 2px outside its edge. From the first pointer move over the popup (one with real movement) until the next key press the ring stays off: the popup sets data-pointer meanwhile, so the focus Base UI gives the popup when the pointer leaves an item draws no ring. |
Menu.Item | A single actionable menu entry. |
Menu.Separator | Horizontal divider between groups of items. |
Menu.Group | Semantic grouping wrapper for related items. |
Menu.GroupLabel | Non-interactive label for a Menu.Group. |
Menu.CheckboxItem | Menu item with a toggleable checked state. |
Menu.CheckboxItemIndicator | Visual indicator shown when CheckboxItem is checked. |
Menu.RadioGroup | Enforces single selection among RadioItem children. |
Menu.RadioItem | Selectable item within a Menu.RadioGroup. |
Menu.RadioItemIndicator | Visual indicator shown when RadioItem is selected. |
Menu.Arrow | Arrow on the popup edge that faces the trigger, in the popup’s --popover background and --border colour. Place it inside Menu.Content. In RTL it needs dir="rtl" on <html> or <body>. The menu moves out by the arrow’s length, so sideOffset stays the gap between the trigger and the arrow’s tip. The arrow stays at least arrowPadding pixels from the menu’s ends, clear of the rounded corner. The default is the menu’s corner radius plus 0.21 × the arrow’s size (about 10 in the default theme). It is read when the menu mounts and again when a Menu.Arrow mounts or unmounts in it (not after a runtime --radius change), so it follows --radius, --spacing and a rounded-* class on Menu.Content. With an arrow, the focus ring is drawn on the menu’s ::after, above the arrow. It is the same ring as without an arrow, and the ::after takes the menu’s border width, so restyle it with classes under the same has-[.PopupArrow]:focus-visible:after: prefix (for example has-[.PopupArrow]:focus-visible:after:outline-destructive), or remove it with focus-visible:after:hidden. |
Menu.Content Props
All other props are forwarded to the underlying Base UI Menu.Popup.
Menu.Item Props
All props are forwarded to the underlying Base UI Menu.Item.