Menubar

Desktop-style menu bar.

Usage

Compose Root > Menu > (Trigger + Content). Menu pairs one trigger with its panel; a menubar holds several. Give Root an aria-label.

Menubar vs Dropdown Menu

A menubar is not a row of Dropdown Menus. Two behaviours make it a single control rather than several:

  • Arrow keys move between the top-level menus, so the whole bar is one tab stop.
  • Once one menu is open, hovering a sibling switches to it — no second click. That is the desktop-app behaviour people already expect from a menu bar.

Build it from separate dropdowns and you lose both, which is exactly the kind of regression nobody notices with a mouse.

Shared menu parts

Item, Group, Label and Separator are the same components Dropdown Menu and Context Menu use. Bits re-exports identical menu internals to all three, so the three menus look and behave the same by construction rather than by three copies of the same CSS agreeing for now.

They stay context-aware — the same wrapper emits data-menubar-item here.

When not to use it

A menubar is a desktop-application pattern. On a website it is usually the wrong shape.

It assumes a pointer that hovers and a screen wide enough for several always-visible triggers — neither holds on a phone. For site navigation reach for a Navigation Menu; for a handful of actions on a toolbar, a Dropdown Menu or Toolbar. Use a menubar when you are genuinely building an application chrome — an editor, an IDE-like tool.

Props

Menubar.Root

PropTypeDefault
class Extra classes merged onto the menubar.string—
child bits-ui Snippet<[{ props: Record<string, unknown>; }]> | undefined—
children bits-ui Snippet<[]> | undefined—
dir bits-ui The reading direction of the menubar.Direction | undefined—
id bits-ui string | undefined—
loop bits-ui When `true`, the roving focus will loop back to the first menu item when the last menu item is reached and vice verse.boolean | undefined—
onValueChange bits-ui A callback that is called when the active menu changes.OnChangeFn<string> | undefined—
ref bits-ui HTMLElement | null | undefined—
value bits-ui The 'value' assigned to the currently active menu in the menubar.string | undefined—

Menubar.Menu

PropTypeDefault
children bits-ui Snippet<[]> | undefined—
onOpenChange bits-ui A callback that is called when the menu is opened or closed.OnChangeFn<boolean> | undefined—
value bits-ui The `value` assigned to the menu. Used to programmatically control the menu's open state within the menubar.string | undefined—

Menubar.Trigger

PropTypeDefault
class Extra classes merged onto the trigger.string—
child bits-ui Snippet<[{ props: Record<string, unknown>; }]> | undefined—
children bits-ui Snippet<[]> | undefined—
disabled bits-ui Whether the trigger for the menubar item is disabled.boolean | null | undefinedfalse
id bits-ui string | undefined—
ref bits-ui HTMLElement | null | undefined—

Menubar.Content

PropTypeDefault
class Extra classes merged onto the menu panel.string—
align bits-ui The preferred alignment of the anchor to render against when open. This may change when collisions occur."start" | "center" | "end" | undefined—
alignOffset bits-ui An offset in pixels from the "start" or "end" alignment options.number | undefined—
arrowPadding bits-ui This describes the padding between the arrow and the edges of the floating element. If your floating element has border-radius, this will prevent it from overflowing the corners.number | undefined—
avoidCollisions bits-ui When `true`, overrides the `side` and `align` options to prevent collisions with the boundary edges.boolean | undefinedtrue
child bits-ui Snippet<[FloatingContentSnippetProps & { props: Record<string, unknown>; }]> | undefined—
children bits-ui Snippet<[]> | undefined—
collisionBoundary bits-ui A boundary element or array of elements to check for collisions against.Arrayable<Boundary> | undefined—
collisionPadding bits-ui The amount in pixels of virtual padding around the viewport edges to check for overflow which will cause a collision.number | Partial<Record<"top" | "right" | "bottom" | "left", number>> | undefined8
customAnchor bits-ui Use an element other than the trigger to anchor the content to. If provided, the content will be anchored to the provided element instead of the trigger. You can pass a selector string or an HTMLElement.string | HTMLElement | Measurable | null | undefined—
dir bits-ui The text direction of the content.Direction | undefined—
escapeKeydownBehavior bits-ui Escape behavior type. `close`: Closes the element immediately. `defer-otherwise-close`: Delegates the action to its parent component that has an escape keydown handler. If no parent is found, it closes the element. `defer-otherwise-ignore`: Delegates the action to the parent element. If no parent is found, nothing is done. `ignore`: Prevents the element from closing and also blocks the parent element from closing in response to an escape key press.EscapeBehaviorType | undefined`close`
forceMount bits-ui Whether to force mount the component.boolean | undefined—
hideWhenDetached bits-ui boolean | undefined—
id bits-ui string | undefined—
interactOutsideBehavior bits-ui Interact outside behavior type. `close`: Closes the element immediately. `defer-otherwise-close`: Delegates the action to the parent element. If no parent is found, it closes the element. `defer-otherwise-ignore`: Delegates the action to the parent element. If no parent is found, nothing is done. `ignore`: Prevents the element from closing and also blocks the parent element from closing in response to an outside interaction.InteractOutsideBehaviorType | undefined`close`
loop bits-ui When `true`, the menu will loop through items when navigating with the keyboard.boolean | undefinedfalse
onCloseAutoFocus bits-ui Event handler called when auto-focusing on close. Can be prevented.EventCallback | undefined—
onEscapeKeydown bits-ui Callback fired when escape is pressed.((e: KeyboardEvent) => void) | undefined—
onFocusOutside bits-ui Callback fired when focus leaves the dismissible layer.((event: FocusEvent) => void) | undefined—
onInteractOutside bits-ui Callback fired when an outside interaction event completes, which is either a `pointerup`, `mouseup`, or `touchend` event, depending on the user's input device.InteractOutsideEventHandler | undefined—
onOpenAutoFocus bits-ui Event handler called when auto-focusing on open. Can be prevented.EventCallback | undefined—
preventOverflowTextSelection bits-ui Passing `true` will prevent the overflow of text selection outside the element, provided the element is the top layer.boolean | undefined`true`
preventScroll bits-ui Whether to prevent scrolling the body when the content is open. Whether to prevent body scrolling when the content is open.boolean | undefinedtrue
ref bits-ui HTMLElement | null | undefined—
side bits-ui The preferred side of the anchor to render against when open. Will be reversed when collisions occur."top" | "right" | "bottom" | "left" | undefined—
sideOffset bits-ui The distance in pixels from the anchor to the floating element.number | undefined—
sticky bits-ui "partial" | "always" | undefined—
strategy bits-ui The positioning strategy to use for the floating element."absolute" | "fixed" | undefined—
trapFocus bits-ui Whether focus is trapped within the focus scope.boolean | undefinedfalse
updatePositionStrategy bits-ui "optimized" will only update the position when necessary, while "always" will update the position on each animation frame, which is useful if the floating content is following something like a mouse cursor."always" | "optimized" | undefined"optimized"

Menubar.Item (shared)

PropTypeDefault
class Extra classes merged onto the item.string—
child bits-ui Snippet<[{ props: Record<string, unknown>; }]> | undefined—
children bits-ui Snippet<[]> | undefined—
closeOnSelect bits-ui Whether or not the menu item should close when selected.boolean | undefinedtrue
disabled bits-ui When `true`, the user will not be able to interact with the menu item.boolean | undefinedfalse
id bits-ui string | undefined—
onSelect bits-ui A callback fired when the menu item is selected. Prevent default behavior of selection with `event.preventDefault()`.((event: Event) => void) | undefined—
ref bits-ui HTMLElement | null | undefined—
textValue bits-ui Optional text to use for typeahead filtering. By default, typeahead will use the `.textContent` of the menu item. When the content is more complex, you can provide a string here instead.string | undefinedundefined

Menubar.Trigger

Menubar.Content

Menu, Sub, SubTrigger, SubContent, CheckboxItem, RadioItem, RadioGroup and Arrow are re-exported from Bits unchanged.