Menus
Files: src/config/menu.en.json, src/config/menu.fr.json · Skill level: Beginner
The header menu and the footer link columns live in one JSON file per language. menu.en.json is the English menu and menu.fr.json the French one. Keep the two files in the same shape: same items, same order, same URLs. Only the name and label texts differ.
Each file has two lists:
{ "header": [ ... ], "footer": [ ... ]}Header Menu
Each item in header is one entry in the top menu. A trimmed copy of the shipped English menu:
"header": [ { "enable": true, "name": "Services", "url": "/services/", "hasChildren": true, "source": "trades", "limit": 6, "children": [ { "enable": true, "name": "Who we serve", "url": "/industries/" }, { "enable": true, "name": "How it works", "url": "/how-it-works/" } ] }, { "enable": true, "name": "Pricing", "url": "/pricing/" }, { "enable": true, "name": "Areas", "url": "/areas/", "hasChildren": true, "source": "areas", "limit": 8 }, { "enable": true, "name": "Reviews", "url": "/reviews/", "class": "hidden xl:flex" }, { "enable": true, "name": "Company", "hasChildren": true, "children": [ { "enable": true, "name": "About us", "url": "/about/" }, { "enable": true, "name": "Projects", "url": "/projects/" }, { "enable": true, "name": "Contact", "url": "/contact/" } ] }]| Key | What it does |
|---|---|
enable | false hides the item without deleting it |
name | The text in the menu |
url | Where it links. Write paths without the language: /pricing/, not /fr/pricing/. The French menu adds /fr/ itself. A dropdown with a url also marks itself active on the pages under it |
hasChildren | true makes the item a dropdown |
children | The links inside the dropdown, each with enable, name, and url |
source | "trades" builds the Services mega menu from your services; "areas" lists your service areas. See Header & Mobile Bar |
limit | With source: the most services per trade (6) or areas (8) shown |
class | Extra classes for the item. "hidden xl:flex" hides Reviews below 1320 px, where the bar runs out of room |
Dropdowns With Labelled Columns
A child that has its own hasChildren and children becomes a labelled column in the dropdown. Its name is the small heading above the column. The Pages menu uses this to list every page of the theme in five columns:
{ "enable": true, "name": "Pages", "hasChildren": true, "children": [ { "enable": true, "name": "Homepages", "hasChildren": true, "children": [ { "enable": true, "name": "Main homepage", "url": "/" }, { "enable": true, "name": "Cleaning company", "url": "/home-cleaning/" }, { "enable": true, "name": "Commercial cleaning", "url": "/home-commercial/" }, { "enable": true, "name": "Handyman", "url": "/home-handyman/" } ] }, { "enable": true, "name": "Booking & help", "hasChildren": true, "children": [ { "enable": true, "name": "Book", "url": "/book/" }, { "enable": true, "name": "Contact", "url": "/contact/" } ] } ]}Plain links and labelled columns can be mixed in one dropdown: the plain links come first, as one column without a heading. A dropdown of plain links only is one list, split into two columns above eight links. On phones, the columns become lists inside the mobile menu.
Footer Menus
footer is a list of link columns. Each has a label (the column heading) and a list of links:
"footer": [ { "label": "Services", "list": [ { "enable": true, "name": "All services", "url": "/services/" }, { "enable": true, "name": "Standard clean", "url": "/services/standard-cleaning/" }, { "enable": true, "name": "Deep clean", "url": "/services/deep-cleaning/" } ] }, { "label": "Areas", "source": "areas", "list": [{ "enable": true, "name": "All areas", "url": "/areas/" }] }, { "label": "Legal", "list": [ { "enable": true, "name": "Terms", "url": "/terms-conditions/" }, { "enable": true, "name": "Privacy policy", "url": "/privacy-policy/" }, { "enable": true, "name": "Cookie settings", "url": "#cookie-settings" } ] }]The shipped file has five columns: Services, Company, Help, Areas, and Legal. Two rules matter:
- The last column holds the legal links. Every footer layout shows it in its bottom row, next to the copyright, instead of as a column. Keep Legal last.
"source": "areas"lists your service areas first, then the column’s own links (“All areas”). Thelargefooter turns this column into a row of areas.
Each footer layout uses the columns a little differently: default puts the first column (Services) in two columns beside your contact details, minimal shows the first two, and columns shows up to three link columns plus your contact details. See Footer & CTA Band.
The Cookie settings link (#cookie-settings) reopens the cookie banner. If you turn the banner off in [settings.cookieConsent], set this item’s enable to false.
Keep Both Languages In Step
npm run check-i18n (also part of npm run astro-check) compares menu.fr.json with menu.en.json and reports a difference in the number of items, a url, or a source. So when you add, remove, or move a menu item, do it in both files.
JSON is strict: every item but the last in a list needs a comma after it, and every name and URL needs double quotes. A missing comma stops the site from building. See File Formats.
Do It With AI
In src/config/menu.en.json and menu.fr.json: set "enable": false on the "Pages" header item,remove [ITEMS] from the Company dropdown, and add a header link "[NAME]" ("[FRENCH NAME]") to[URL] after Pricing. In the footer, make the Services column list only: [SERVICES]. Keep theLegal column last and the Areas column's "source": "areas". Keep both files in the samestructure, then run npm run check-i18n.