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

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. For a shorter guide to the menu files in this theme, 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.

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.

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

{ "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:

{
"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:

{
"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 for the details.

FieldUsed onWhat it does
enableEverythingtrue shows the item and false hides it
nameEverythingThe text shown
weightEverythingA position number. Keep it in step with the order in the file, because some themes sort by it
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, weight, and children
descriptionMega menu linksA short line about the link, where your theme shows one
iconMega menu linksAn icon name or an image path, depending on the theme
ctaMega menusA card with enable, eyebrow, image, title, description, items, and button
barMega menusA strip with enable, text, label, and url
badgeLinksA small label or dot beside the name, with enable, type, label, and color. Copy the shape from your menu file if it has one

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

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

FileWhat it does
src/layouts/components/global/header/Navbar.astroThe menu in the header
src/layouts/components/global/header/MenuItem.astroOne top-level item
src/layouts/components/global/header/NavStage.astroThe shared panel and its script
src/layouts/components/global/header/NavStageDropdown.astroDropdown content
src/layouts/components/global/header/NavStageList.astroThe list that repeats for each nested level
src/layouts/components/global/header/NavStageMega.astroMega menu content
src/styles/navigation.cssThe .nav-stage styles
src/lib/utils/navigationActive.tsMarks the current page in the menu

Do It With AI

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.
Type something to search...