menu

Semantic container for toolbar buttons and context menu patterns. Provides structure for groups of interactive commands.

Description

The <menu> element represents a group of commands or options. While its original purpose was for context menus, it's now primarily used as a semantic container for toolbar buttons and action menus.

In Vanilla Breeze, <menu> is styled as a flexible container with variants for different menu patterns: toolbars, context menus, vertical menus, and icon button groups.

HTML Semantics

The <menu> element is semantically equivalent to <ul> but signals to assistive technologies that the items represent commands rather than list content. It's the appropriate choice for groups of actions.

When to Use

  • Toolbars: Groups of action buttons in editors or applications
  • Context menus: Dropdown menus with actions
  • Action lists: Vertical lists of commands
  • Button groups: Related buttons that function as a unit
  • Filter controls: Pill-style toggles for filtering content

When Not to Use

  • For navigation links - use <nav> instead
  • For content lists - use <ul> or <ol>
  • For dropdown selection - use <select>

Variants

Default Menu

The default menu displays as a horizontal flexbox container.

  • <menu> <li><button type="button">Action 1</button></li> <li><button type="button">Action 2</button></li> <li><button type="button">Action 3</button></li> </menu>

    .toolbar

    Horizontal toolbar with background and contained button styling.

  • <menu class="toolbar"> <li><button type="button" class="ghost">Bold</button></li> <li><button type="button" class="ghost">Italic</button></li> <li><button type="button" class="ghost">Underline</button></li> <li><button type="button" class="ghost">Link</button></li> </menu>

    .context

    Dropdown-style context menu with separators.

  • <menu class="context"> <li><button type="button">Cut</button></li> <li><button type="button">Copy</button></li> <li><button type="button">Paste</button></li> <li role="separator"></li> <li><button type="button">Select All</button></li> </menu>

    .context with Links

    Context menus can also contain links for navigation actions.

    .vertical

    Vertical menu layout for sidebar or dropdown patterns.

  • <menu class="vertical"> <li><button type="button" class="ghost">Dashboard</button></li> <li><button type="button" class="ghost">Projects</button></li> <li><button type="button" class="ghost">Tasks</button></li> <li><button type="button" class="ghost">Settings</button></li> </menu>

    .icons

    Icon-only toolbar with square icon buttons.

  • <menu class="toolbar icons"> <li> <button type="button" class="ghost" aria-label="Bold"> <svg ...>...</svg> </button> </li> ... </menu>

    .pills

    Pill-shaped buttons for filter or toggle patterns.

  • <menu class="toolbar pills"> <li><button type="button" class="ghost">All</button></li> <li><button type="button">Active</button></li> <li><button type="button" class="ghost">Completed</button></li> </menu>

    .compact

    Reduced spacing for dense interfaces.

  • <menu class="context compact"> <li><button type="button">Item 1</button></li> ... </menu>

    Styling

    CSS Implementation

    menu { display: flex; flex-wrap: wrap; gap: var(--size-xs); margin: 0; padding: 0; list-style: none; & > li { margin: 0; } } /* Toolbar variant */ menu.toolbar { display: flex; align-items: center; gap: var(--size-2xs); padding: var(--size-2xs); background: var(--color-surface-raised); border-radius: var(--radius-m); & > li > button { padding: var(--size-xs); min-inline-size: auto; background: transparent; color: var(--color-text); &:hover { background: var(--color-surface); } } } /* Context menu variant */ menu.context { flex-direction: column; gap: 0; padding: var(--size-2xs); background: var(--color-surface); border: var(--border-width-thin) solid var(--color-border); border-radius: var(--radius-m); box-shadow: 0 4px 12px oklch(0% 0 0 / 0.15); min-inline-size: 160px; & > li[role="separator"] { block-size: 1px; margin-block: var(--size-2xs); background: var(--color-border); } }

    Variant Classes Summary

    Class Description
    .toolbar Horizontal toolbar with background container
    .context Dropdown-style menu with shadow and separators
    .vertical Vertical stacking layout
    .icons Square icon-only buttons
    .pills Pill-shaped button items
    .compact Reduced spacing and font size

    Menu Separators

    Use role="separator" on list items to create visual dividers in context menus.

  • <menu class="context"> <li><button type="button">Edit</button></li> <li><button type="button">Duplicate</button></li> <li role="separator"></li> <li><button type="button">Move to folder</button></li> ... </menu>

    Accessibility

    Semantic Structure

    The menu element conveys that its items are commands. Each <li> should contain a <button> or <a> for proper interaction.

    ARIA Roles

    • role="separator" - Marks visual dividers between groups of items
    • aria-label - Use on icon-only buttons to describe the action
    • aria-disabled - For non-functional menu items

    Icon Buttons

    When using icon-only buttons, always include an aria-label for screen reader users:

    <button type="button" class="ghost" aria-label="Bold"> <svg ...>...</svg> </button>

    Keyboard Navigation

    Menu buttons receive standard keyboard focus. For more complex menu patterns with arrow key navigation, consider using ARIA menu roles or a JavaScript-enhanced component.

    Key Action
    Tab Move focus between menu buttons
    Enter / Space Activate focused button

    Combining Variants

    Variants can be combined for different effects.

    Toolbar + Icons + Pills
  • Context + Compact
  • Related Elements

    • <button> - Primary interactive element inside menu items
    • <nav> - For navigation links (not commands)
    • <ul> - For non-command list content
    • <dialog> - For modal menus or action sheets

    Browser Support

    The <menu> element is supported in all browsers. Its semantic meaning is recognized by screen readers, though the element renders identically to <ul> by default.