Navigation

The primary navigation is the menu in the site header. It is driven entirely by each language’s menu.main configuration: top-level entries render as links, and an entry with children becomes a dropdown submenu on desktop. Below 48rem, a menu button keeps the header to the brand and the button; the opened panel contains the primary links, search, and language controls.

This page’s own header renders the live component — on this site the menu holds Documentation and BHDicaire.com.

Example#

Variants#

  • Desktop: direct links stay in the header; an item with one level of children reveals its submenu on hover or keyboard focus
  • Mobile: the brand and menu button stay in the header; the opened panel contains every primary link, the search trigger, and the language switcher
  • Active state: the current section receives the accent rule; child links use their own active class

When to use#

  • The header only: layouts/partials/header.html renders the strip on every page, and no other template reuses it
  • Links live in configuration, never in the template — config/_default/languages.yml for the main site, config/brand/languages.yml for the brand site, one menu per language
  • One level of children only: an entry with children becomes a desktop dropdown and an expanded mobile group; anything deeper never renders
  • The active state is computed per section, so a blog post highlights Blog without any per-page declaration

Implementation#

menu:
  main:
    - identifier: docs
      name: Documentation
      pageRef: /docs
      weight: 10
    - identifier: main-site
      name: BHDicaire.com
      url: https://bhdicaire.com/en/
      weight: 20

initNavDropdowns() manages desktop submenu state. initMobileNavigation() controls the header menu button and closes the panel on Escape or when the desktop breakpoint is restored.

ContextTriggerResult
Desktop submenuHover or keyboard focusThe child panel opens and the parent link receives aria-expanded="true"
Desktop submenuEscapeThe child panel closes and focus returns to the parent link
Mobile headerMenu buttonThe primary links, search, and language controls become visible; the button state and label update
Mobile headerEscape or viewport changeThe mobile panel closes; Escape returns focus to the menu button

The markup in layouts/partials/header.html walks .Site.Menus.main, computes active state from the current section, and wraps an item with children in .nav-menu and .nav-submenu. The same partial places the search trigger and language switcher inside the mobile panel. The manifest lists every static i18n key this component uses; labels from menu.main remain configuration data, not i18n keys in the template.

Options#

OptionPurpose
identifierStable key; also what the active-state rules in the template match against
nameVisible link text, per language
pageRefContent path of the target page; a bad path fails the build
urlExternal or literal URL, for entries that point off-site
parentMakes the entry a child of another; one level only
weightSort order within the menu

Interface manifest

Kind
Component
Category
Navigation
Status
Implemented
Implementation
Partial:layouts/partials/header.htmlCSS:assets/css/site.cssJavaScript:assets/js/site.jsi18n:mainNavigationnavigationMenuOpennavigationMenuCloseConfiguration:config/_default/languages.ymlconfig/brand/languages.yml
Used by
layouts/partials/header.html

Accessibility#

  • The menu button has an accessible label from navigationMenuOpen or navigationMenuClose, controls the primary-navigation panel, and exposes its state with aria-expanded
  • The strip is a single <nav> landmark, localized through the mainNavigation i18n key, which distinguishes it from the header’s language switcher and the footer’s navigation landmarks
  • A desktop parent entry stays a real link and carries aria-haspopup="true", so it both signals the submenu and works as a destination in its own right; initNavDropdowns() keeps its aria-expanded synchronized with visible desktop submenu state
  • Keyboard: Tab reaches the menu button and then the opened controls; Escape closes an open mobile panel or desktop submenu and returns focus to its trigger
  • Avoid nesting menu entries more than one level deep — the template renders a single pass over .Children, so a third level would silently never appear