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

Header & Mobile Action Bar

Files: src/config/config.toml, src/config/menu.en.json, src/i18n/en.json, src/content/sections/english/announcement-bar.md, page frontmatter · Skill level: Beginner

Every header has the logo, the menu with its Services and Areas dropdowns, your phone number, the light/dark button, and one main button (“Get a price”). On phones the menu folds into a menu button, and a bar with Call and the main button sits at the bottom of the screen. Homio has four header layouts and an optional announcement bar above them.

Homio header with the Services menu open

Choose A Header Layout

src/config/config.toml
[settings.layout]
# default | logo, menus with dropdowns (trades mega menu, areas), phone pill, sunflower button
# simple | the same menus, phone, one button; transparent over a full-bleed hero photo (`band` hero)
# centered | a white rounded bar floating over the hero photo, menus centred, phone, button
# utility | a brand-green strip with a call line above a bar with the menus and one green button
header = "default"
LayoutWhat it looks likeDemo page
defaultA white bar: logo, menu, phone pill, light/dark button, and the large sunflower button at the end. Used by the inner pages/
simpleThe same menu, phone, and a smaller button. Above a band hero (a full-width photo) it is transparent with white links, and turns solid once the page scrolls. On any other page it is a plain solid bar/home-handyman/
centeredA white rounded bar that floats over the hero photo, with the menu in the middle/home-cleaning/
utilityA slim brand-green strip with “Need help this week? Call us: (number)” above a white bar with the menu and one green button. The phone pill moves into the strip/home-commercial/

One page, another layout. Add headerLayout to the page’s frontmatter. It wins over [settings.layout] header:

---
title: "Handyman"
headerLayout: "simple" # default | simple | centered | utility
---

The demo homepages set their own this way (src/content/homepage/english/home-*.md), and so does /elements/. A misspelled value is caught by npm run astro-check in files with a schema. The simple layout is meant for pages that open with the band hero; see Homepages.

The utility strip’s text comes from utilityBar.help and utilityBar.callUs in src/i18n/en.json and fr.json. The strip and the announcement bar scroll away; only the main bar stays pinned.

The Services Mega Menu

The Services item fills itself from your services: one column per trade (Cleaning, Repairs, Windows, Carpets, Outdoor), with the trade name as a small heading and up to six services under it. A row at the bottom holds All services and the item’s own links (“Who we serve”, “How it works”).

It comes from this item in src/config/menu.en.json:

{
"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/" }
]
}
  • "source": "trades" builds the columns from src/content/services/: the trades and their order from trades: in services/english/-index.md, and each service from its trade and order fields. A new service appears in the menu without a menu edit. A service with draft: true is left out.
  • "limit" is the most services shown per trade.
  • "children" are the extra links in the bottom row.

The Areas Menu

{
"enable": true,
"name": "Areas",
"url": "/areas/",
"hasChildren": true,
"source": "areas",
"limit": 8
}

"source": "areas" lists your service areas from src/content/areas/, in their order, up to limit, then an All areas (4) link to /areas/. Above six areas the list splits into two columns. Add or remove an area file and the menu follows. See Service Areas.

The other dropdowns (Company, Pages) are plain lists you write yourself: see Menus.

On wide screens all dropdowns open in one panel under the header: hover or click an item, and move between items without the panel closing. The keyboard works too: Enter or Space on a menu item opens it, Tab moves through its links, and Esc closes it.

The Phone Pill

The round phone icon in the header calls [business] phone. From 1320 px wide it also shows phoneDisplay beside the icon. It is hidden when phone is empty, and the utility layout shows the number in its green strip instead. On an area page with its own local number, the header uses that number. See Business Info.

The Main Button

[settings.navigationButton]
enable = true
label = "" # i18n `navigation.buttonLabel` ("Get a price"); a value here replaces it in every language
url = "/book/" # Primary header button, hidden on this page itself; the mobile action bar uses the same button

To change the words in both languages, edit navigation.buttonLabel in src/i18n/en.json (“Get a price”) and src/i18n/fr.json (“Obtenir un prix”). The button is hidden on the page it links to, so /book/ doesn’t show a button to itself.

A different button on one page. A primaryCta block in the page’s frontmatter changes the header button, the phone action bar, the announcement link, and the footer link to the booking page, on that page only. The commercial homepage uses it to send every action to its walkthrough form:

primaryCta:
label: "Request a walkthrough"
url: "#walkthrough" # a section id on this page, or a path
announcement: "hide" # link (swap the bar's booking link) | hide | keep

A text link before the button. [settings.navigationSecondaryLink] adds a plain link (“Contact”) before the button in every header layout, from 1320 px wide. It ships off:

[settings.navigationSecondaryLink]
enable = false
label = "" # navigation.secondaryLabel ("Contact")
url = "/contact/"
[settings]
stickyHeader = true # Keeps the header pinned while scrolling (the announcement bar scrolls away)

With true, the header stays at the top while you scroll, and a thin line appears under it once the page moves. false lets it scroll away with the page.

The Announcement Bar

A thin bar above the header for an offer or a notice, with one link and a close button. It ships off. Turn it on in src/content/sections/english/announcement-bar.md (and french/):

---
enable: false # Show the strip above the header on every page
id: "autumn-2026" # Change it when the message changes: visitors who closed the old one see the new one
text: "Autumn deep cleans: book by **Oct 31** and get the oven clean free." # Inline markdown and {phone} work
link:
enable: true
label: "Price your visit"
url: "/book/"
dismissible: true # Visitors can close it; the choice is kept in their browser
start: "" # Optional first day, YYYY-MM-DD
end: "2026-10-31" # Optional last day, YYYY-MM-DD
hideOn: ["/book/"] # Path prefixes where the bar stays hidden (no language prefix)
tone: "ink" # ink | mist
---
  • tone: ink is a near-black bar, mist a light green one.
  • start and end show the bar only between those dates. end is also checked in the visitor’s browser, so an old build doesn’t show an expired offer.
  • The text is a sample offer: replace it, or keep enable: false.

The Mobile Menu

Below 1024 px wide, the menu links fold into a menu button (three lines) at the right of the header. It opens a full panel with:

  • the menu items. Dropdowns open as lists inside the panel, with the trades and areas
  • a Call button and the main button, side by side
  • the language switch (En / Fr) and the light/dark button

The Mobile Action Bar

On phones (below 768 px), a bar is fixed to the bottom of the screen with Call and the main button, so a visitor can call or get a price from anywhere on the page.

Homio on a phone with the Call and Get a price bar at the bottom

src/config/config.toml
[settings.mobileActionBar]
enable = true
showCall = true # Phone from [business] phone; hidden when it is empty
showText = false # Text-message button; needs [business] sms
hideOn = [
"/book/",
"/contact/",
] # Path prefixes where the bar is not rendered (language prefix ignored)
hideNearFooter = true # Slide away while the footer is visible
  • The main button is the header’s ([settings.navigationButton], or the page’s primaryCta).
  • showText = true adds a Text button that opens a text message to [business] sms. The bar then has three buttons.
  • hideOn leaves the bar out on pages that already are the action. "/book/" also covers /book/thanks/, and /fr/book/ in French.
  • The bar also slides away while a form field has focus, and while the menu or a dialog is open. The cookie banner and the back-to-top button sit above it.
  • The button labels are mobileBar.call and mobileBar.text in the i18n files.

Files For Developers

All in src/layouts/components/global/: header/Header.astro picks the layout and adds the announcement bar and the utility strip, header/SiteHeader.astro draws the bar, the dropdown panel, and the mobile menu, header/MegaTrades.astro and header/MegaAreas.astro are the Services and Areas panels, header/UtilityBar.astro is the green strip, and MobileActionBar.astro is the bottom bar. The announcement bar is src/layouts/components/widgets/AnnouncementBar.astro. The menu data is built in src/lib/utils/menu.ts, and the styles are in src/styles/navigation.css.

Do It With AI

Set the header to the [default | simple | centered | utility] layout in [settings.layout] of
src/config/config.toml, and list the page files that set their own headerLayout. Change the
header button: url "[URL]" in [settings.navigationButton], and navigation.buttonLabel in
src/i18n/en.json and fr.json to "[LABEL]" / "[FRENCH LABEL]". Keep the label short enough for
the mobile action bar.
Turn on the announcement bar: in src/content/sections/english/announcement-bar.md and
french/, set enable: true, text "[TEXT]", the link "[LABEL]" to [URL], end "[YYYY-MM-DD]",
and a new id. On phones, also show a Text button in the mobile action bar
([settings.mobileActionBar] showText = true) with our text number [NUMBER] in [business] sms.
Type something to search...