# Navigation & Mega Menus

## Navigation & Mega Menus

**Files:** `src/config/menu.<lang>.json` (Astro and Tina editions) · **Skill level:** Beginner

The header menu is built from one file per language. You write the links, and the theme handles the dropdown panel, the flyouts, the mobile menu, and keyboard support. For the header layout, the logo, and the header button, see [Header](../../customization/header/). For a shorter guide to the menu files in this theme, see [Menus](../../customization/menus/).

<Aside type="note">
  This page shows the menu file. In the Tina edition, you edit the same fields
  in the menus entry at `/admin/`. In the Sanity edition, the menu is a **Menus**
  document for each language in the Studio, with plain labels for the same
  options.
</Aside>

### How The Menu Behaves
On large screens:

- All dropdowns and mega menus share one panel. Moving from one menu to the next, the panel changes width, height, and position in about 300ms, and the content slides in the direction you moved.
- Opening a menu from closed animates it in without that change of shape.
- A nested item opens a flyout beside its list, as deep as your data goes. A flyout that would run off the screen opens on the other side.
- Moving the mouse diagonally from a link to its flyout doesn't close it.

On small screens the menu is a slide-in panel. Submenus open and close with a height animation, and focus stays inside the panel while it is open.

Visitors who turn on **reduce motion** in their device settings get a simple fade instead. In right-to-left languages everything mirrors: see [RTL & Arabic](../rtl-arabic/).

### The Menu File
There is one file for each language, such as `src/config/menu.en.json` and `src/config/menu.ar.json`. The header menu is the `headerPrimary` list.

There are three kinds of item.

**1. A plain link**

```json
{ "enable": true, "name": "Contact", "weight": 4, "url": "/contact/" }
```

**2. A dropdown.** Set `"hasChildren": true` and list the links in `children`. A child can have its own `"hasChildren": true` and `children`, which opens a flyout. You can keep nesting, because the depth follows your data. In the Tina edition, the form reaches at least four levels:

```json
{
  "enable": true,
  "name": "Pages",
  "weight": 2,
  "hasChildren": true,
  "children": [
    { "enable": true, "name": "About", "weight": 1, "url": "/about/" },
    {
      "enable": true,
      "name": "Company",
      "weight": 2,
      "hasChildren": true,
      "children": [
        {
          "enable": true,
          "name": "Careers",
          "weight": 1,
          "hasChildren": true,
          "children": [
            { "enable": true, "name": "Open roles", "weight": 1, "url": "/careers/" }
          ]
        }
      ]
    }
  ]
}
```

**3. A mega menu.** Set `"hasMegaMenu": true` and list groups of links in `menus`. You can add a `cta` card and a `bar` strip along the bottom of the panel:

```json
{
  "enable": true,
  "name": "Services",
  "weight": 3,
  "hasMegaMenu": true,
  "menus": [
    {
      "enable": true,
      "name": "Popular",
      "weight": 1,
      "children": [
        {
          "enable": true,
          "name": "Consulting",
          "description": "A short line about this link",
          "icon": "House",
          "url": "/services/consulting/",
          "weight": 1
        }
      ]
    }
  ],
  "cta": {
    "enable": true,
    "eyebrow": "New",
    "image": "/images/your-photo.jpg",
    "title": "Card title",
    "description": "One short sentence.",
    "items": ["First point", "Second point"],
    "button": { "enable": true, "label": "Get in touch", "url": "/contact/" }
  },
  "bar": {
    "enable": false,
    "text": "Not sure what you need?",
    "label": "Talk to us",
    "url": "/contact/"
  }
}
```

Mega menu links differ by theme. Some themes show `description` and some don't, and `icon` is either an icon name or an image path, sometimes used only in the mobile menu. Copy what your theme's menu file does, and see [Menus](../../customization/menus/) for the details.

### Menu Fields
| Field         | Used on                  | What it does                                                                                                 |
| ------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------ |
| `enable`      | Everything               | `true` shows the item and `false` hides it                                                                   |
| `name`        | Everything               | The text shown                                                                                               |
| `weight`      | Everything               | A position number. Keep it in step with the order in the file, because some themes sort by it                |
| `url`         | Links                    | `/pricing/` for your own pages (the language prefix is added for you), or a full `https://` address          |
| `hasChildren` | Dropdowns, flyouts       | `true` when the item has `children`                                                                          |
| `children`    | Dropdowns, mega groups   | The links inside. Items in a dropdown can have their own `children`                                          |
| `hasMegaMenu` | Top-level items          | `true` when the item opens a mega menu                                                                       |
| `menus`       | Mega menus               | The groups of links. Each group has `enable`, `name`, `weight`, and `children`                               |
| `description` | Mega menu links          | A short line about the link, where your theme shows one                                                      |
| `icon`        | Mega menu links          | An icon name or an image path, depending on the theme                                                        |
| `cta`         | Mega menus               | A card with `enable`, `eyebrow`, `image`, `title`, `description`, `items`, and `button`                      |
| `bar`         | Mega menus               | A strip with `enable`, `text`, `label`, and `url`                                                            |
| `badge`       | Links                    | A small label or dot beside the name, with `enable`, `type`, `label`, and `color`. Copy the shape from your menu file if it has one |

<Aside type="caution">
  Change the menu file of **every language** when you add or remove a link, so
  the menus stay in step. JSON is strict: a missing comma or a comma after the
  last item stops the site from building.
</Aside>

### Keyboard Support
This works with no setup. Keep it working if you change the markup.

| Key                 | What it does                                       |
| ------------------- | -------------------------------------------------- |
| `Enter` or `Space`  | Opens the menu on the focused item                 |
| `Down` and `Up`     | Move through the links in the open list            |
| `Left` and `Right`  | Move between menus and in and out of flyouts       |
| `Home` and `End`    | Jump to the first or last link in the list         |
| `Tab`               | Moves into the panel, in reading order             |
| `Escape`            | Closes the menu and returns focus to where it was  |

Moving focus out of the menu closes it. In the mobile panel, `Escape` closes the panel and returns focus to the button that opened it.

### Files For Developers
| File                                                     | What it does                                 |
| -------------------------------------------------------- | -------------------------------------------- |
| `src/layouts/components/global/header/Navbar.astro`      | The menu in the header                       |
| `src/layouts/components/global/header/MenuItem.astro`    | One top-level item                           |
| `src/layouts/components/global/header/NavStage.astro`    | The shared panel and its script              |
| `src/layouts/components/global/header/NavStageDropdown.astro` | Dropdown content                        |
| `src/layouts/components/global/header/NavStageList.astro` | The list that repeats for each nested level |
| `src/layouts/components/global/header/NavStageMega.astro` | Mega menu content                           |
| `src/styles/navigation.css`                              | The `.nav-stage` styles                      |
| `src/lib/utils/navigationActive.ts`                      | Marks the current page in the menu           |

### Do It With AI
```text
Add a mega menu called "[NAME]" to the header. Use the menu files in src/config/, one for each
language listed in src/config/language.json. Add it to headerPrimary with "hasMegaMenu": true and
[NUMBER] groups in "menus", linking to these pages: [PAGES]. Keep the same item shape as the
existing items. Translate the names for each language. Don't change the navigation components.
Then run npm run astro-check.
```