# Page titles that are the same on every page

Source: https://easeweb.dev/learn/page-title
Topics: Page structure > Every page has a unique title (WCAG 2.4.2)
The fix: Give every page a title that names it before the site name. Either set the title in each page's template, so the server sends it with the page, or, in a single-page app, set document.title in the router every time the view changes. Both pass; which one applies depends on how the site renders its pages.
Test with: screen reader
References: https://www.w3.org/WAI/WCAG22/Understanding/page-titled.html https://www.w3.org/WAI/WCAG22/Techniques/html/H25 https://www.w3.org/WAI/WCAG22/Techniques/general/G88 https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/title https://developer.mozilla.org/en-US/docs/Web/API/Document/title

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

Someone shopping at a garden centre's online shop opens a few pages in new tabs to compare them: spring bulbs, the basket and the contact page. Every tab reads "Fernway Garden". To find the basket, they click through the tabs one by one. A screen reader user who switches windows hears "Fernway Garden" each time and has to read into the page to learn where they are. Their browser history and bookmarks fill with the same name, so going back to a page they saw yesterday means opening each entry.

## Why it fails

The shop is a single-page app, and this is the most common way such apps fail 2.4.2. The browser loads one HTML file, whose shared layout sets `<title>Fernway Garden</title>`. After that, the router swaps the content on the client without loading a new page, so nothing ever replaces the title unless the app's own code does. Sites rendered on the server rarely fail this way, since each page arrives with its own `<title>`; in a single-page app, a fresh project starts with this failure until someone wires titles into the router. Each page loads with a title, so the page is "titled" in the narrowest sense, but the title does not describe it. WCAG 2.4.2 asks that each page has a title that describes its topic or purpose. A title that is the same on the basket and on a product list describes neither.

## Who is affected

The failure grows with each page open at once: one tab is easy to keep track of, five identical ones are not. Narrow tabs on a laptop or a phone's tab switcher show only the first few words of a title, so a title that starts with the site name fails in the same way even when the rest of it differs.

## What automation and AI miss

A page-level check such as axe's `document-title` looks at one page at a time and asks only whether the title exists and is not empty, so every page here passes. Site crawlers, many of them built for search engine work, do report titles repeated across URLs; run one, since it finds this failure across a whole site. Neither kind of tool judges whether a title describes its page: "Page 2" or a route name like "basket-view" passes both. A crawler also loads each URL fresh, so it does not see a title that goes stale after moving through the app, for example one that stays on the previous view after Back. A suggested fix needs the same check: a title set in the shared layout only repeats the failure. Check the titles after you move through the app, not only on the page you opened.

## Before: one title for every page

```html
<!-- app.html, the shared layout -->
<head>
  <title>Fernway Garden</title>
</head>
```

```js
router.afterEach(() => {
  // content changes; the title stays
});
```

Every view, from a product list to the basket, has the same title. Nothing tells a tab, a bookmark or a screen reader which page this is.

## After: a title in each page's template

```html
<!-- basket page -->
<head>
  <title>Basket – Fernway Garden</title>
</head>
```

```html
<!-- product list page -->
<head>
  <title>Spring bulbs – Fernway Garden</title>
</head>
```

Each page sends its own title in its HTML, so it is there before any script runs and in every browser. The page's name comes first, so it stays visible in a narrow tab and is the first thing a screen reader says.

## After: in a single-page app, the router sets the title on every route change

```js
const SITE = 'Fernway Garden';

router.afterEach(route => {
  document.title = `${route.meta.title} – ${SITE}`;
});
```

```js
{ path: '/basket', component: Basket, meta: { title: 'Basket' } }
```

Every route declares its name, and the title changes each time the view does, including on Back and Forward. This works only as long as every route has a `title`: give the router a test or a type check that fails when one is missing, rather than falling back to the site name. Render the same title on the server too, if the app has server rendering, so it is right on the first load.

## Which option to use

Both pass 2.4.2. A title in each template is the simplest when the server renders each page: there is no script to fail and nothing to keep in step. A single-page app that swaps views on the client has no new HTML to carry a title, so it needs the router to set one; most frameworks offer a head component (`<svelte:head>`, Next.js `metadata`, Angular's `title` on a route) that does this and renders it on the server as well. Use whichever matches how your pages are built; many sites use both.

## Implementation decisions

Put the page first and the site name last, separated by a dash or a bar: "Basket – Fernway Garden". People recognise the site already; what they need is which page. For a page inside a section, go from the most specific to the least: "Tulip mix – Spring bulbs – Fernway Garden".

Pages that share one template need something that tells them apart. Some ways to do that:

- search results include the query and, if it helps, the count: "Results for tulips (24) – Fernway Garden";
- each step of a checkout says which step it is: "Delivery, step 2 of 4 – Fernway Garden";
- a form returned with errors starts with "Error:", so people hear it before anything else.

Keep the title short: the first 30 or so characters do most of the work in tabs and search results. Don't stuff it with keywords; that helps nobody find the page. Write it in the page's language, and translate it with the rest of the page.

A dialog or a panel that opens inside a page does not need its own title; a view with its own URL does. Changing the title does not by itself tell a screen reader user that the view changed; announcing the new view and moving focus is a separate task, covered under page changes.

## Verify the fix

1. Load several pages directly, by URL, and check that each title is present, different, and starts with the page's own name.
2. Move between views with the site's own links, then with Back and Forward, and check that the title follows each change.
3. Open five or more pages in tabs, narrow the window, and check that the tabs can still be told apart.
4. With a screen reader, load a page and switch to its window from another, and check that the title it reads names the page.
5. Open the browser history or a bookmark list and check that the entries for different pages differ.

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat when routes or templates are added.

## Limits

This is a starting pattern, not a guarantee for every application. Whether a title describes a page is a judgement no tool makes; read the titles as a visitor would. Apps that open content in iframes or new windows need titles there too. Test the complete journey on your real pages.
