Navigation & Mega Menus
Files: src/config/menu.<language>.json · 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 layouts and the header button, see Header. For the footer link columns and a shorter guide to the menu files, see Menus.
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.
Below 1024 px, the menu button opens a menu card over the page. Work, Services, and Pages open and close inside it with a height animation, the card ends with the header button, your email with a copy button, the social links, and the light/dark and language buttons, and focus stays inside the card while it is open.
Visitors who turn on reduce motion in their device settings get a simple fade instead. On Arabic pages everything mirrors: see RTL & Arabic.
The Menu File
There is one file for each language: src/config/menu.en.json, menu.fr.json, and menu.ar.json. The header menu is the headerPrimary list. The same file also holds the footer link columns (see Menus).
Items show in the order of the file. There are three kinds of item.
1. A plain link
{ "enable": true, "name": "About", "url": "/about/" }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. The shipped Work menu goes three levels deep: case studies by discipline, then the projects:
{ "enable": true, "name": "Work", "hasChildren": true, "children": [ { "enable": true, "name": "All projects", "url": "/projects/" }, { "enable": true, "name": "Archive", "url": "/archive/" }, { "enable": true, "name": "Case studies", "hasChildren": true, "children": [ { "enable": true, "name": "Branding", "hasChildren": true, "children": [ { "enable": true, "name": "Marrow Kiln", "url": "/projects/ceramic-forms/" }, { "enable": true, "name": "Ravel & Hue", "url": "/projects/colour-fan/" } ] } ] }, { "enable": true, "name": "Photo series", "hasChildren": true, "children": [ { "enable": true, "name": "North Atlantic", "url": "/projects/north-atlantic/" } ] } ]}An item with children opens its menu and has no link of its own. To link to the page it stands for, add it as the first child, as “All projects” does above.
3. A mega menu. Set "hasMegaMenu": true and list groups of links in menus. Groups sit side by side. You can add a cta card beside them and a bar strip along the bottom of the panel. This is the shipped Services menu, shortened:
{ "enable": true, "name": "Services", "hasMegaMenu": true, "menus": [ { "enable": true, "name": "", "children": [ { "enable": true, "name": "Brand identity", "url": "/services/brand-identity/", "description": "Marks, type, and colour" }, { "enable": true, "name": "Web design", "url": "/services/web-design/", "description": "Calm, fast websites" } ] } ], "cta": { "enable": true, "project": "ceramic-forms", "eyebrow": "", "image": "", "title": "", "button": { "enable": false, "label": "", "url": "" } }, "bar": { "enable": true, "links": [ { "enable": true, "name": "Pricing", "url": "/pricing/" }, { "enable": true, "name": "FAQ", "url": "/faq/" } ] }}Pages is the other mega menu. It has three groups (Homes, Pages, More), no card, and a strip with the site search and a link to /elements/:
"bar": { "enable": true, "links": [ { "enable": true, "name": "Search", "action": "search", "shortcut": "⌘K" }, { "enable": true, "name": "Every section layout", "url": "/elements/" } ]}The Project Card
cta shows one project as a card beside the links: its cover, its title, and its year, linking to the project page.
projectis the file name of a project insrc/content/projects/<language>/, without.md, such as"ceramic-forms".- Leave
projectempty to use the first project withfeatured: true. The demo marksceramic-formsas featured. image,title, andeyebrowreplace the project’s cover, title, and year when you fill them in.button.urlreplaces the link whenbutton.enableistrue.- If
projectmatches no file, the card shows only when you fill intitleandbutton.urlyourself.
The card doesn’t show description or items. They are kept so the menu files have the same shape as in other themes.
The Bottom Strip
bar is a strip along the bottom of a mega menu. Its links are quick links, shown in a row. A link with "action": "search" instead of a url is a button that opens the site search, and shortcut is the key hint shown beside it on large screens. The search button shows only while [settings.search] enable is true (see Search).
bar also takes text (a short line) and label with url (one link before the quick links). The demo leaves them empty.
Menu Fields
| Field | Used on | What it does |
|---|---|---|
enable | Everything | false hides the item. An item without enable shows |
name | Everything | The text shown. On a mega menu group it is the small heading, and can be empty |
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, and children |
description | Dropdown and mega links | A short line under the link, on large screens |
cta | Mega menus | The project card: enable, project, eyebrow, image, title, and button |
bar | Mega menus | The bottom strip: enable, links (each with enable, name, and url or action, plus shortcut), and the optional text, label, and url |
badge | Dropdown links | A small label or dot beside the name on large screens, with enable, type, label, and color |
No menu link has an icon, and the header has no field for one. The mega menu groups in the shipped files still have a weight number, kept for the standard menu shape. The header doesn’t read weight or icon: to move an item, move it in the file.
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 |
On Arabic and other right-to-left pages, Left and Right swap, so they follow the reading direction. 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.
The menu components are in src/layouts/components/global/header/.
Do It With AI
Add a mega menu called "[NAME]" to the header of my Margo site. Use the menu files in src/config/,one for each language listed in src/config/language.json (menu.en.json, menu.fr.json,menu.ar.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 thenames for each language. Don't change the navigation components. Then run npm run astro-check.