Repeated navigation must keep the same relative order across pages. Examples for city sites built from several systems.
If the main menu on one page reads Services, Departments, Contact and on the next page reads Departments, Contact, Services, every visit starts with a search. WCAG 2.1 success criterion 3.2.3 (Level AA) says that navigational mechanisms repeated on multiple pages within a set of pages must occur in the same relative order each time, unless the user changes it.
"Relative order" is the key phrase. The mechanism may gain items, sub-menus may expand and secondary navigation may appear on deeper pages. What must stay stable is the order of the items that are repeated. Users can also change the order themselves through adaptive technology or preferences, and that is not a violation.
Municipal websites are often stitched together from a main site, a permit system, a library catalog and a utility portal, each built by a different team. The header menu is similar but not the same, and the order of items drifts. A resident moving from the city homepage to the "Pay a bill" portal sees a different menu in a different order, and a screen reader user has to relearn the page. WCAG applies within a "set of web pages", and a single agency's services usually count as one set. Where a third-party portal is part of the service you provide, see vendors and third-party content.
<!-- home.html -->
<nav><a href="/services">Services</a><a href="/departments">Departments</a><a href="/contact">Contact</a></nav>
<!-- permits.html -->
<nav><a href="/departments">Departments</a><a href="/contact">Contact</a><a href="/services">Services</a></nav><!-- layout.html, included by every template -->
<header>{% include "main-nav.html" %}</header>
<!-- main-nav.html -->
<nav aria-label="Main">
<a href="/services">Services</a>
<a href="/departments">Departments</a>
<a href="/contact">Contact</a>
</nav>footerLinks: ["Privacy", "Accessibility", "Sitemap"] // page A
footerLinks: ["Sitemap", "Privacy", "Accessibility"] // page B// site-config.json, one source for all pages
{ "footerLinks": ["Privacy", "Accessibility", "Sitemap"] }<!-- on /departments/parks -->
<nav>
<a href="/departments/parks/events">Events</a>
<a href="/contact">Contact</a>
<a href="/services">Services</a>
</nav><!-- on /departments/parks -->
<nav>
<a href="/services">Services</a>
<a href="/departments">Departments</a>
<ul>
<li><a href="/departments/parks/events">Events</a></li>
</ul>
<a href="/contact">Contact</a>
</nav>// SwiftUI: tab order depends on which screen builds it
TabView {
if isHome { HomeView().tabItem { Label("Home", systemImage: "house") } }
ReportsView().tabItem { Label("Reports", systemImage: "doc") }
if !isHome { HomeView().tabItem { Label("Home", systemImage: "house") } }
}// SwiftUI: one source of order (tab.view and tab.label are app-defined helpers on AppTab)
enum AppTab: CaseIterable { case home, reports, account }
TabView {
ForEach(AppTab.allCases, id: \.self) { tab in
tab.view.tabItem { tab.label }
}
}// Jetpack Compose: items built separately per screen
NavigationBar {
if (onHome) NavigationBarItem(...Home...)
NavigationBarItem(...Reports...)
if (!onHome) NavigationBarItem(...Home...)
}// Jetpack Compose
val destinations = listOf(Home, Reports, Account) // defined once
NavigationBar {
destinations.forEach { d ->
NavigationBarItem(
selected = current == d,
onClick = { navigate(d) },
icon = { Icon(d.icon, contentDescription = null) },
label = { Text(d.label) }
)
}
}