Skip to content
New: Customize your theme with an AI assistant. Read the guide

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.

  • project is the file name of a project in src/content/projects/<language>/, without .md, such as "ceramic-forms".
  • Leave project empty to use the first project with featured: true. The demo marks ceramic-forms as featured.
  • image, title, and eyebrow replace the project’s cover, title, and year when you fill them in. button.url replaces the link when button.enable is true.
  • If project matches no file, the card shows only when you fill in title and button.url yourself.

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.

FieldUsed onWhat it does
enableEverythingfalse hides the item. An item without enable shows
nameEverythingThe text shown. On a mega menu group it is the small heading, and can be empty
urlLinks/pricing/ for your own pages (the language prefix is added for you), or a full https:// address
hasChildrenDropdowns, flyoutstrue when the item has children
childrenDropdowns, mega groupsThe links inside. Items in a dropdown can have their own children
hasMegaMenuTop-level itemstrue when the item opens a mega menu
menusMega menusThe groups of links. Each group has enable, name, and children
descriptionDropdown and mega linksA short line under the link, on large screens
ctaMega menusThe project card: enable, project, eyebrow, image, title, and button
barMega menusThe bottom strip: enable, links (each with enable, name, and url or action, plus shortcut), and the optional text, label, and url
badgeDropdown linksA 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.

KeyWhat it does
Enter or SpaceOpens the menu on the focused item
Down and UpMove through the links in the open list
Left and RightMove between menus and in and out of flyouts
Home and EndJump to the first or last link in the list
TabMoves into the panel, in reading order
EscapeCloses 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 the
names for each language. Don't change the navigation components. Then run npm run astro-check.
Type something to search...