Skip to content
Entangle UI v0.13.0

MenuBar

Application menu bar component for editor interfaces. Provides dropdown menus with items, sub-menus, separators, and keyboard shortcut labels. Supports full keyboard navigation with arrow keys and automatic menu switching on hover when a menu is open.

Live Preview

import { MenuBar } from 'entangle-ui';
<MenuBar>
<MenuBar.Menu label="File">
<MenuBar.Item onClick={handleNew} shortcut="Ctrl+N">
New
</MenuBar.Item>
<MenuBar.Item onClick={handleOpen} shortcut="Ctrl+O">
Open
</MenuBar.Item>
<MenuBar.Separator />
<MenuBar.Item onClick={handleSave} shortcut="Ctrl+S">
Save
</MenuBar.Item>
<MenuBar.Item onClick={handleSaveAs} shortcut="Ctrl+Shift+S">
Save As...
</MenuBar.Item>
</MenuBar.Menu>
<MenuBar.Menu label="Edit">
<MenuBar.Item onClick={handleUndo} shortcut="Ctrl+Z">
Undo
</MenuBar.Item>
<MenuBar.Item onClick={handleRedo} shortcut="Ctrl+Shift+Z">
Redo
</MenuBar.Item>
<MenuBar.Separator />
<MenuBar.Item onClick={handleCut} shortcut="Ctrl+X">
Cut
</MenuBar.Item>
<MenuBar.Item onClick={handleCopy} shortcut="Ctrl+C">
Copy
</MenuBar.Item>
<MenuBar.Item onClick={handlePaste} shortcut="Ctrl+V">
Paste
</MenuBar.Item>
</MenuBar.Menu>
</MenuBar>

MenuBar uses a compound component pattern with the following sub-components:

| Component | Purpose | | ---------------------- | --------------------------------------------------- | | MenuBar.Menu | Top-level dropdown trigger and container | | MenuBar.Item | Clickable menu item with optional icon and shortcut | | MenuBar.CheckboxItem | Toggleable item with a reserved check-mark gutter | | MenuBar.RadioGroup | Owns the selected value for a set of radio items | | MenuBar.RadioItem | Single-select item within a RadioGroup | | MenuBar.Sub | Nested sub-menu with hover-to-open behavior | | MenuBar.Separator | Visual divider between menu items |

The size prop controls the overall density of the menu bar.

Sizes

<MenuBar size="sm">
<MenuBar.Menu label="File">{/* ... */}</MenuBar.Menu>
</MenuBar>
<MenuBar size="md">
<MenuBar.Menu label="File">{/* ... */}</MenuBar.Menu>
</MenuBar>

| Size | Use case | | ---- | --------------------------------------- | | sm | Compact layouts, secondary menus | | md | Standard application menu bar (default) |

Use MenuBar.Sub to create nested menus. Sub-menus open on hover with a short delay to prevent accidental closing.

Sub-menus

<MenuBar.Menu label="View">
<MenuBar.Item onClick={handleZoomIn}>Zoom In</MenuBar.Item>
<MenuBar.Item onClick={handleZoomOut}>Zoom Out</MenuBar.Item>
<MenuBar.Separator />
<MenuBar.Sub label="Layout">
<MenuBar.Item onClick={() => setLayout('single')}>Single</MenuBar.Item>
<MenuBar.Item onClick={() => setLayout('split')}>Split View</MenuBar.Item>
<MenuBar.Item onClick={() => setLayout('quad')}>Quad View</MenuBar.Item>
</MenuBar.Sub>
</MenuBar.Menu>

Items can display an icon before the label text.

Menu Items with Icons

import { SaveIcon, CopyIcon } from 'entangle-ui';
<MenuBar.Item onClick={handleSave} icon={<SaveIcon />} shortcut="Ctrl+S">
Save
</MenuBar.Item>
<MenuBar.Item onClick={handleCopy} icon={<CopyIcon />} shortcut="Ctrl+C">
Copy
</MenuBar.Item>

Use MenuBar.CheckboxItem for independent toggles and MenuBar.RadioGroup + MenuBar.RadioItem for single-select options. Both reserve a leading gutter so checked and unchecked rows stay aligned on their label. By default they keep the menu open on activation (closeOnClick={false}) so several options can be set in one pass; pass closeOnClick to close after a selection. Each supports both controlled (checked / value) and uncontrolled (defaultChecked / defaultValue) use, mirroring the navigation Menu.

Checkable & Radio Items

const [showGrid, setShowGrid] = useState(true);
const [shading, setShading] = useState('solid');
<MenuBar.Menu label="View">
<MenuBar.CheckboxItem checked={showGrid} onCheckedChange={setShowGrid}>
Show Grid
</MenuBar.CheckboxItem>
<MenuBar.Separator />
<MenuBar.RadioGroup value={shading} onValueChange={setShading}>
<MenuBar.RadioItem value="solid">Solid</MenuBar.RadioItem>
<MenuBar.RadioItem value="wireframe">Wireframe</MenuBar.RadioItem>
<MenuBar.RadioItem value="rendered">Rendered</MenuBar.RadioItem>
</MenuBar.RadioGroup>
</MenuBar.Menu>;

Both menus and individual items can be disabled.

Disabled Items

<MenuBar.Menu label="File">
<MenuBar.Item onClick={handleSave} shortcut="Ctrl+S">Save</MenuBar.Item>
<MenuBar.Item disabled>Export (unavailable)</MenuBar.Item>
</MenuBar.Menu>
<MenuBar.Menu label="Debug" disabled>
{/* Entire menu is disabled */}
</MenuBar.Menu>

The menuOffset prop controls the vertical gap between the top-level trigger and the dropdown panel.

Menu Offset

<MenuBar menuOffset={4}>
<MenuBar.Menu label="File">{/* ... */}</MenuBar.Menu>
</MenuBar>
Prop Type Default Description
size 'sm' | 'md' 'md' Size of the menu bar, controlling overall density.
menuOffset number 2 Vertical gap in pixels between the trigger button and the dropdown panel.
children ReactNode — MenuBar.Menu components.
className string — Additional CSS class names.
style CSSProperties — Inline styles.
testId string — Test identifier for automated testing.
ref Ref<HTMLDivElement> — Ref to the root element.
Prop Type Default Description
label * string — Text displayed on the trigger button.
disabled boolean false Whether the entire menu is disabled.
children ReactNode — Menu items (MenuBar.Item, MenuBar.Sub, MenuBar.Separator).
className string — Additional CSS class names.
style CSSProperties — Inline styles.
testId string — Test identifier for automated testing.
ref Ref<HTMLDivElement> — Ref to the menu container element.
Prop Type Default Description
children ReactNode — Item label text.
onClick () => void — Click handler. The menu closes automatically after the handler fires.
shortcut string — Keyboard shortcut display text (e.g., "Ctrl+S"). This is a visual label only and does not bind the shortcut.
icon ReactNode — Icon element displayed before the label.
disabled boolean false Whether the item is disabled.
className string — Additional CSS class names.
style CSSProperties — Inline styles.
testId string — Test identifier for automated testing.
ref Ref<HTMLButtonElement> — Ref to the button element.
Prop Type Default Description
children ReactNode — Item label text.
checked boolean — Controlled checked state.
defaultChecked boolean false Uncontrolled initial checked state.
onCheckedChange (checked: boolean) => void — Called when the checked state toggles.
indicator ReactNode <CheckIcon /> Indicator shown in the leading gutter when checked.
shortcut string — Keyboard shortcut display text (visual only).
closeOnClick boolean false Whether activating the item closes the menu.
disabled boolean false Whether the item is disabled.
Prop Type Default Description
value string — Controlled selected value.
defaultValue string — Uncontrolled initial value.
onValueChange (value: string) => void — Called when the selected value changes.
children ReactNode — MenuBar.RadioItem elements.
Prop Type Default Description
children ReactNode — Item label text.
value * string — Value this item represents within its RadioGroup.
indicator ReactNode <CircleIcon /> Indicator shown in the leading gutter when selected.
shortcut string — Keyboard shortcut display text (visual only).
closeOnClick boolean false Whether activating the item closes the menu.
disabled boolean false Whether the item is disabled.
Prop Type Default Description
label * string — Sub-menu trigger label text.
disabled boolean false Whether the sub-menu is disabled.
children ReactNode — Sub-menu items.
className string — Additional CSS class names.
style CSSProperties — Inline styles.
testId string — Test identifier for automated testing.
ref Ref<HTMLDivElement> — Ref to the sub-menu container element.
Prop Type Default Description
className string — Additional CSS class names.
style CSSProperties — Inline styles.
testId string — Test identifier for automated testing.
ref Ref<HTMLDivElement> — Ref to the separator element.
  • The root element has role="menubar" and is focusable with tabIndex={0}
  • Menu triggers use role="menuitem" with aria-haspopup="true" and aria-expanded
  • Dropdown panels use role="menu" with aria-label set to the trigger label
  • Full keyboard navigation:
    • ArrowLeft / ArrowRight to move between top-level menus
    • ArrowDown / ArrowUp to navigate items within a dropdown (including checkbox and radio items)
    • Enter / Space to open a menu or activate an item
    • Escape to close the current dropdown and return focus to the trigger
  • When a menu is open, hovering over another trigger automatically switches to that menu
  • Separators use role="separator"
  • Sub-menus use aria-haspopup="true" and aria-expanded on their trigger
  • MenuBar.CheckboxItem uses role="menuitemcheckbox" with aria-checked; MenuBar.RadioItem uses role="menuitemradio" with aria-checked, wrapped in a MenuBar.RadioGroup (role="group")

MenuBar defines no component-level CSS custom properties of its own; it is re-skinned entirely through the shared --etui-* theme tokens below.

| Token | Used for | | --------------------------------------- | --------------------------------- | | --etui-shell-menubar-bg | Bar background | | --etui-shell-menubar-text | Bar text color | | --etui-shell-menubar-height | Bar height (size="md") | | --etui-shell-menubar-hover-bg | Trigger hover fill | | --etui-shell-menubar-active-bg | Open-trigger fill | | --etui-shell-menubar-shortcut-text | Shortcut label color | | --etui-color-bg-elevated | Dropdown / sub-menu surface | | --etui-color-border-default | Dropdown border, separators | | --etui-color-border-focus | Focus outline | | --etui-color-surface-hover | Dropdown item hover/focus fill | | --etui-color-text-primary | Dropdown item text | | --etui-color-text-secondary | Checkbox / radio indicator gutter | | --etui-radius-md / --etui-radius-sm | Dropdown / trigger corner radius | | --etui-shadow-lg | Dropdown elevation | | --etui-z-dropdown | Dropdown stacking order |