import * as MenuStories from './menu.component.stories';
# Menu
## Example
Click the trigger, then use the arrow keys or type to move between items.
## Usage
```tsx
import { Icon } from '@clerk/mosaic/components/icon';
import { Menu } from '@clerk/mosaic/components/menu';
import { LogOut } from '@clerk/mosaic/icons/glyphs/log-out';
import { Plus } from '@clerk/mosaic/icons/glyphs/plus';
import { X } from '@clerk/mosaic/icons/glyphs/x';
Add organization
Sign out
Delete user
;
```
`Menu.Popup` renders the portal and the floating positioner itself — neither is a part you compose
— so items are the only children you write.
### Trigger
With no children, `Menu.Trigger` renders a square ghost `Button` holding an ellipsis glyph. Pass
children for a labelled trigger, or `render` to supply your own element — it receives the computed
props (ARIA attributes, click and keyboard handlers) to spread.
```tsx
Actions
} />
```
### Items
`label` names the item for typeahead and for assistive technology. Compose the row with
`Menu.Label` and optional `Menu.Media` and `Menu.Indicator` parts. Text dropped straight into the
item is not a flex child the row can size, so it neither lines up with the other rows nor
truncates. A row with nothing to lead it is `Menu.Label` alone. Use
`color='negative'` for destructive actions; the color is inherited by the children. `disabled` items
are skipped by keyboard navigation and their `onClick` never fires. Activating an item closes the
menu; pass `closeOnClick={false}` to keep it open.
```tsx
Revoke
Delete
```
### Media
`Menu.Media` is a square leading column that centers whatever it holds — an icon, an image, an
avatar. Items that lead with marks of differing widths need it: without it each row sets its own
text start, and the labels no longer line up. Leave it empty on an item that leads with nothing and
that row keeps the column. It renders a `span`, since the item it sits in is a button.
`size` is the column's width: `sm` (the default) fits an icon or an avatar, `xs` a bare glyph. The
row has no height of its own, so it takes whatever the media asks for. That makes the size a
per-menu decision rather than a per-item one: give every item in one menu the same value, or their
text no longer starts on one line.
```tsx
```
### Label
`Menu.Label` takes the space between the media and whatever trails it, and truncates its text to one
line. Items whose text is a name — an account, an organization — need it most: a long name would widen
the menu instead of ellipsing. It is also what pushes a trailing mark to the end of the row. Use it
for every composed item, so rows built from parts all read the same.
### Indicator
`Menu.Indicator` is a square trailing column for a mark at the end of the row, such as a check or a
spinner. It keeps its width while empty, so render it on any item whose mark can appear later and
the label does not shift when it does.
Together they make a row that leads with an avatar and trails with a check:
```tsx
C
colin@clerk.dev
```
### Placement
`Menu.Root` takes `placement` and `sideOffset`; the popup flips and shifts automatically to stay in
view, and its `max-height` tracks the available space so long menus scroll rather than overflow.
```tsx
…
;
```
`sideOffset` also takes `{ x, y }`, one gap per axis, for a menu that can flip between the two: what
it has to clear sideways is not what it has to clear above. `fallbackPlacements` names where it goes
when `placement` does not fit, in the order it tries them, instead of the opposite side. A menu
opened from inside another floating surface wants both — the opposite side is that surface, so it
has to be given somewhere else to land.
```tsx
…
;
```
### Open on hover
`openOnHover` opens the menu when a mouse rests on the trigger, and closes it when the mouse leaves
for anywhere other than the menu. The path from the trigger to the menu is kept open, so the mouse
can cross the gap diagonally. A press still opens it, and keeps a hover-opened menu open until the
next press or an outside click. Touch and keyboard open it as usual.
```tsx
…
```
Inside a popover, closing the menu leaves the popover open.
### Scrolling
A menu with more items than fit gets the shared ScrollArea treatment rather than a bare scrollbar:
the rows fade out at whichever edge still has content past it, and the thumb lifts as the pointer
enters. Nothing to opt into — `Menu.Popup` composes it.
The popup itself only supplies the chrome and the height cap; the rows scroll in a `menu-viewport`
inside it. They cannot be one element, because the fade is a `mask-image` and a mask on the popup
would clip its own background and drop shadow along with the overflowing rows.
### Controlled
```tsx
const [open, setOpen] = useState(false);
…
;
```
## Parts
| Part | Slot | Description |
| ---------------- | -------------------------------- | ------------------------------------------------------------------------------- |
| `Menu.Root` | — | State provider; owns open/close, placement, and keyboard navigation. |
| `Menu.Trigger` | `menu-trigger` | Opens the menu. Defaults to a square ghost `Button` with an ellipsis. |
| `Menu.Popup` | `menu-positioner` / `menu-popup` | Portals, positions, and renders the popup surface. |
| ↳ viewport | `menu-viewport` | The scrolling box inside the popup. Carries the ScrollArea fade and scrollbar. |
| `Menu.Item` | `menu-item` | A single action whose content is composed through children. |
| `Menu.Media` | `menu-media` | Square leading column that centers an item's icon, image, or avatar. |
| `Menu.Label` | `menu-label` | The item's text. Fills the row between media and trailing marks, and truncates. |
| `Menu.Separator` | `menu-separator` | Full-bleed divider between groups of items. |
## Styling
The Mosaic menu is themed with **StyleX**. Each styled part
carries a stable `.cl-` class (the slots above) alongside the StyleX atoms. Consumers never
target the hashed atomic classes — override by targeting the `.cl-*` slot from a CSS layer that wins
over `@clerk/mosaic/styles.css`:
```css
@import '@clerk/mosaic/styles.css' layer(components);
@layer overrides {
.cl-menu-popup {
border-radius: 20px;
}
}
```
The popup's enter/exit transition is driven off its own `data-starting-style` /`data-ending-style`
attributes and is disabled under `prefers-reduced-motion: reduce`. Item hover state is gated behind
`@media (hover: hover)`, and the keyboard-active item is styled off `data-active`, so pointer and
keyboard highlighting stay in sync.