# Menubar

A desktop application menu bar presenting a horizontal strip of top-level menus with full keyboard navigation.

```slint
import { Menubar, MenubarMenu } from "@glint/components/menubar.slint";
import { Tokens } from "@glint/theme/tokens.slint";
import { IconSet } from "@lucide";

export component Demo inherits Window {
    width: 560px;
    height: 320px;
    background: Tokens.color-background;

    in-out property <string> last-action: "None";

    VerticalLayout {
        alignment: start;
        spacing: 24px;
        padding: 16px;

        Menubar {
            menus: [
                {
                    label: "File",
                    items: [
                        { label: "New Window", icon: IconSet.AppWindow, shortcut: "Ctrl+Shift+N" },
                        { label: "New File", icon: IconSet.FilePlus, shortcut: "Ctrl+N" },
                        { label: "Open Recent", separator-before: true, children: [
                            { label: "project-a" },
                            { label: "workspace-b" },
                        ]},
                        { label: "Exit", separator-before: true, shortcut: "Ctrl+Q" }
                    ]
                },
                {
                    label: "Edit",
                    items: [
                        { label: "Undo", icon: IconSet.Undo, shortcut: "Ctrl+Z" },
                        { label: "Redo", icon: IconSet.Redo, shortcut: "Ctrl+Y" },
                        { label: "Cut", separator-before: true, icon: IconSet.Scissors, shortcut: "Ctrl+X" },
                        { label: "Copy", icon: IconSet.Copy, shortcut: "Ctrl+C" },
                        { label: "Paste", icon: IconSet.Clipboard, shortcut: "Ctrl+V" },
                    ]
                },
                {
                    label: "View",
                    items: [
                        { label: "Full Screen", shortcut: "F11", checkable: true, checked: false },
                        { label: "Show Minimap", checkable: true, checked: true },
                    ]
                }
            ];
            selected(menu, item, child) => {
                root.last-action = "Menu " + menu + ", Item " + item + (child >= 0 ? (", Subitem " + child) : "");
            }
        }

        VerticalLayout {
            alignment: center;
            spacing: 8px;

            Text {
                text: "Desktop Application Menu Bar";
                color: Tokens.color-foreground;
                font-size: Tokens.typography-body-size;
                horizontal-alignment: center;
            }

            Text {
                text: "Last action: " + root.last-action;
                color: Tokens.color-muted-foreground;
                font-size: Tokens.typography-body-sm-size;
                horizontal-alignment: center;
            }
        }
    }
}
```

## Usage

```slint
import { Menubar, MenubarMenu } from "@glint/components/menubar.slint";

export component AppWindow inherits Window {
    Menubar {
        menus: [
            {
                label: "File",
                items: [
                    { label: "New File", shortcut: "Ctrl+N" },
                    { label: "Save", shortcut: "Ctrl+S" },
                ]
            },
            {
                label: "Edit",
                items: [
                    { label: "Undo", shortcut: "Ctrl+Z" },
                    { label: "Redo", shortcut: "Ctrl+Y" },
                ]
            }
        ];
        selected(menu, item, child) => {
            // handle selection
        }
    }
}
```

`Menubar` renders a top-level application menu bar from an array of `MenubarMenu` structs. Each menu item contains a `label` for the top bar and an array of `MenuEntry` items for the popup menu, powered by [MenuPanel](/docs/components/menu-panel) and following the [grouped rows](/docs/components/select#grouped-rows) model.

The keyboard traversal matches desktop standards: `Tab` enters the menu bar, `←`/`→` step across top-level triggers (and switch between open menus if one is expanded), `↓` or `Enter` opens the focused menu, and `Escape` closes the active menu.

## Examples

### Nested submenus and positioning

Submenus cascade beside the parent item when `children` are present. Use `submenu-side` (`PanelSide.right`, `PanelSide.left`) and `submenu-align` (`PanelAlign.start`, `PanelAlign.center`, `PanelAlign.end`) to position nested panels.

```slint
import { Menubar } from "@glint/components/menubar.slint";
import { PanelSide, PanelAlign } from "@glint/components/panel.slint";
import { Tokens } from "@glint/theme/tokens.slint";
import { IconSet } from "@lucide";

export component Demo inherits Window {
    width: 560px;
    height: 320px;
    background: Tokens.color-background;

    VerticalLayout {
        padding: 16px;

        Menubar {
            submenu-side: PanelSide.right;
            submenu-align: PanelAlign.start;
            menus: [
                {
                    label: "Preferences",
                    items: [
                        {
                            label: "Themes",
                            icon: IconSet.Palette,
                            children: [
                                { label: "Dark Modern" },
                                { label: "Light Plus" },
                                { label: "High Contrast" },
                            ]
                        },
                        {
                            label: "Font Size",
                            icon: IconSet.Type,
                            children: [
                                { label: "Small (12px)" },
                                { label: "Medium (14px)" },
                                { label: "Large (16px)" },
                            ]
                        }
                    ]
                }
            ];
        }
    }
}
```

### Checkbox and radio options across menus

Menu rows can hold independent checkable toggles or grouped radio options. Changes update the `menus` property reactively.

```slint
import { Menubar, MenubarMenu } from "@glint/components/menubar.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component Demo inherits Window {
    width: 560px;
    height: 320px;
    background: Tokens.color-background;

    in-out property <[MenubarMenu]> app-menus: [
        {
            label: "Layout",
            items: [
                { label: "Single Column", checkable: true, checked: true, radio-group: "layout" },
                { label: "Two Columns", checkable: true, checked: false, radio-group: "layout" },
                { label: "Grid View", checkable: true, checked: false, radio-group: "layout" },
                { label: "Show Status Bar", separator-before: true, checkable: true, checked: true },
            ]
        }
    ];

    VerticalLayout {
        padding: 16px;

        Menubar {
            menus <=> root.app-menus;
        }
    }
}
```

### Custom menu width floor

Use `min-content-width` to establish the minimum width for dropdown panels across all top-level menus. Panels automatically grow wider if any row requires more horizontal space.

```slint
import { Menubar } from "@glint/components/menubar.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component Demo inherits Window {
    width: 560px;
    height: 320px;
    background: Tokens.color-background;

    VerticalLayout {
        padding: 16px;

        Menubar {
            min-content-width: 260px;
            menus: [
                {
                    label: "Navigation",
                    items: [
                        { label: "Go to Symbol in Workspace…", shortcut: "Ctrl+T" },
                        { label: "Go to Line / Column…", shortcut: "Ctrl+G" },
                    ]
                }
            ];
        }
    }
}
```

## API Reference

### Properties

| Property            | Type                   | Default            | Description                                                                                                                                                                         |
| ------------------- | ---------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `menus`             | `in-out [MenubarMenu]` | no default         | Top-level menus (File / Edit / View / …), each with its own `items`. `in-out` because activating a checkbox or radio row writes its new `checked` back here.                        |
| `min-content-width` | `in length`            | `200px`            | The floor under every open menu's panel width; a panel grows past it to fit its widest row, icon and shortcut hint included.                                                        |
| `submenu-side`      | `in PanelSide`         | `PanelSide.right`  | Where a row's submenu panel opens: which side of the menu, and how it lines up against the row it hangs off. A submenu opens beside its row, so `top` and `bottom` read as `right`. |
| `submenu-align`     | `in PanelAlign`        | `PanelAlign.start` |                                                                                                                                                                                     |
| `highlighted-index` | `in-out int`           | `0`                | Row highlighted by ↑/↓ inside the currently-open popup.                                                                                                                             |
| `focused-index`     | `in-out int`           | `0`                | Trigger the keyboard stands on; consumers rarely set this.                                                                                                                          |

### Callbacks

| Callback                    | Description                                                                                                                                          |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `selected(int , int , int)` | Fired with the menu index, the chosen row's index, and the index of the submenu leaf that was taken or -1 when the row itself was; the popup closes. |

### Enums

| Enum         | Values                           |
| ------------ | -------------------------------- |
| `PanelSide`  | `top`, `right`, `bottom`, `left` |
| `PanelAlign` | `start`, `center`, `end`         |

## Accessibility

- **Top-level menu bar semantics.** Each trigger in the horizontal bar is an accessible button announcing the menu label and whether that menu is expanded (`accessible-expanded`).
- **Menu item semantics.** Open menus render as accessible list structures where items carry their index, name, checkable state, and shortcut descriptions.
- **Keyboard navigation.** `Tab` navigates into the bar. `←`/`→` move focus between menu triggers, automatically opening adjacent menus if a menu is already open. `↑`/`↓` navigate within an open menu. `Escape` closes open submenus and top-level menus.
- **Focus ring.** Menu triggers display a standard theme focus ring when navigated via keyboard.
