# Navigation menus that change order or names between pages

Source: https://easeweb.dev/learn/consistent-navigation
Topics: Menus and navigation > Navigation and controls stay consistent across pages (WCAG 3.2.3, 3.2.4)
The fix: Build every page's header and footer from one shared list of links, the blog's included, so the links keep the same order and the same names everywhere. A page may still add a link or leave one out.
Test with: screen reader, keyboard, zoom
References: https://www.w3.org/WAI/WCAG22/Understanding/consistent-navigation.html https://www.w3.org/WAI/WCAG22/Understanding/consistent-identification.html https://www.w3.org/WAI/WCAG22/Techniques/general/G61 https://www.w3.org/WAI/WCAG22/Techniques/failures/F66 https://www.w3.org/WAI/WCAG22/Techniques/failures/F31

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

## What happens

A homeware shop's pages share a header: the logo, then a menu of Shop, Sale, Journal and About, then Account and Basket. Its Journal, a blog of recipes and stories, runs on a separate blog platform, with a header someone copied from the shop when the blog was set up. Since then, each has been edited on its own. On the Journal, the menu now starts with Journal, "because it's the Journal", and the basket link, which goes to the same page, says Cart. Someone who used the menu on the shop moves to a Journal post and finds the links in a different order, and no Basket.

The same drift turns up in other forms:

- The menu is sorted by popularity, or by what the page is about, so the same links come in a different order on different pages.
- The search button says Search on most pages and Go on the search results page.
- An icon button has a name on most pages and a different one on pages built by another team, such as "Open menu" and "Navigation".

## Why it fails

Two level AA success criteria cover this. 3.2.3, Consistent Navigation, says navigation repeated across a set of pages must come in the same relative order each time, unless the person changes it. 3.2.4, Consistent Identification, says components that do the same thing across a set of pages must be identified consistently: the same job, the same name.

Same relative order doesn't mean identical. A page can add links, such as the Journal's categories, or leave some out, such as the link to the page you are on, and still pass, as long as the links it shares with the other pages come in the same order. Here two shared links have swapped places: Journal comes after Sale on the shop's pages and before Shop on the Journal's. That is failure F66.

Consistent doesn't mean identical either. "Basket (2)" after something is added is still Basket. But Basket and Cart are two names for one link, which is failure F31, and some people won't know they are the same. What makes pages one set is a shared purpose and the same author or organisation, not the platform that serves them: the Journal is the shop's own, at the shop's address and under a copy of the shop's header, so it is part of the same set.

## Who is affected

The pages most likely to differ are the ones built elsewhere: a blog, a help centre, a store locator, each with its own copy of the header.

## What automation and AI miss

Each page's menu is fine on its own, and axe and other scanners test one page at a time; none of their rules covers 3.2.3 or 3.2.4. EaseWeb's audit compares the pages of a run. It reports two repeated links, in the header, a navigation menu or the footer, that come in one order on some pages and the other order on others, and a link to the same address whose name shares no word with its name on most pages. It can't see a link on a page the run didn't visit or on a page without exactly one main landmark, a button that does the same job under another name, or a change only CSS makes, and it only compares the pages it was given, so the Journal must be in the list. A code assistant asked to "add a header to the blog" may write a new one from what it sees, in its own order and its own words.

## Before: the Journal's own copy of the header

```html shop.html
<!-- Every shop page -->
<header class="site-header">
  <a href="/" class="logo">Fernhill</a>
  <nav aria-label="Main">
    <a href="/shop">Shop</a>
    <a href="/sale">Sale</a>
    <a href="/journal">Journal</a>
    <a href="/about">About</a>
  </nav>
  <a href="/account">Account</a>
  <a href="/basket">Basket</a>
</header>
```

```html journal.html
<!-- Every Journal page, from the blog platform's own template -->
<header class="blog-header">
  <a href="/" class="logo">Fernhill</a>
  <nav aria-label="Main">
    <a href="/journal">Journal</a>
    <a href="/shop">Shop</a>
    <a href="/sale">Sale</a>
    <a href="/about">About</a>
  </nav>
  <a href="/account">Account</a>
  <a href="/basket">Cart</a>
</header>
```

The two headers hold the same links, but Journal has moved to the front of the menu, and the link to the basket is called Cart. Each header is correct on its own; together they break both criteria.

## After: one header, from one list of links, on every page

```js nav.js
// The site's header links, in order. The shop and the Journal both render this list.
export const MAIN_NAV = [
  { href: '/shop', label: 'Shop' },
  { href: '/sale', label: 'Sale' },
  { href: '/journal', label: 'Journal' },
  { href: '/about', label: 'About' }
];
export const ACCOUNT_NAV = [
  { href: '/account', label: 'Account' },
  { href: '/basket', label: 'Basket' }
];
```

```html header.html
<!-- What the shared header renders on every page, the Journal's included -->
<header class="site-header">
  <a href="/" class="logo">Fernhill</a>
  <nav aria-label="Main">
    <a href="/shop">Shop</a>
    <a href="/sale">Sale</a>
    <a href="/journal" aria-current="page">Journal</a>
    <a href="/about">About</a>
  </nav>
  <a href="/account">Account</a>
  <a href="/basket">Basket</a>
</header>
```

Both platforms build the header from the same two lists, so the Journal can't put its own link first or name the basket differently without changing it for every page. On a Journal page, the Journal link is marked as the current page, which can change how it looks and is read but not where it sits; how to mark it is in [navigation that marks the current page only by its look](/learn/current-page). If the Journal needs more, such as a row of its categories, it adds them after the shared menu; adding links keeps the order of the ones that are shared.

## Implementation decisions

How the blog gets the shared header depends on the platform:

- A blog the shop's own code renders: use the shop's header component, as every other page does.
- A blog platform with its own templates: generate its header from the same list at build time, or have the platform read the list from a file the shop publishes, rather than editing a copy.
- A hosted service that only takes HTML, such as a help centre: paste in the header the shop renders, and re-paste it whenever the list changes. This is the weakest of the three, because nothing keeps the copy in step; check it after every change to the menu.

Keep the order fixed. A menu sorted by popularity, by what is on sale this week or by the page's own section changes its order from page to page, even when every link is the same. Put changing links in a section of their own, outside the menu that repeats.

Keep each name, and the accessible name of an icon button, the same in every template. A count added to a name, such as "Basket (2)", is fine, because the name still says what it is. Different words are not, even when they mean the same thing to the people who wrote them: pick one, and use it everywhere, including in the footer and on the mobile menu.

On a phone, the menu often moves into a menu button. That is a different layout, so compare pages at the same width, but at that width every page must order and name the links the same way too.

Don't reorder the menu with CSS `order`, `flex-direction: row-reverse` or grid placement on some pages. Screen readers and keyboards follow the source, so the menu looks consistent but isn't read that way, or the other way round.

The same holds for help links and contact details, which 3.2.6 asks to keep in the same place; see [help links that move from page to page](/learn/consistent-help).

## Verify the fix

1. List the links repeated in the header, the navigation menus and the footer, from the home page, a product page, a Journal post, the basket and an error page.
2. For each pair of repeated links, confirm they come in the same order on every page that has both, in the source as well as on screen.
3. For each repeated link and button, confirm it has the same name on every page, apart from a count or state, in what is shown and in what a screen reader reads.
4. Check pages served by any other platform in particular: the blog, a help centre, a store locator.
5. With a screen reader, list the links on each of those pages and confirm the repeated ones come in the same order with the same names.

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after any change to the menu, the templates or a platform the site uses.

## Limits

This is a starting pattern, not a guarantee for every site. The criteria ask for consistency, not for a good menu: links that are the same everywhere can still be hard to understand. They cover one set of pages, so a site that forms a set of its own, such as a blog on a subdomain, written by other people and with a different navigation, can have its own menu, as long as it keeps it consistent. Changes people make themselves, such as a reader view or a menu they rearrange in their settings, are allowed. Test the whole site, page type by page type, with the people and tools your users rely on.

---

Get this guide in your coding agent: MCP https://easeweb.dev/mcp (setup at https://easeweb.dev/services/developers)
