# Navigation that marks the current page only by its look

Source: https://easeweb.dev/learn/current-page
Topics: Menus and navigation > The current page is marked (WCAG 1.3.1)
The fix: Mark the current page's link in the code as well as on screen. Either add aria-current="page" to it and draw the visual style from that attribute, or, where the menu cannot take attributes, add visually hidden text such as "(current page)" inside the link.
Test with: screen reader, keyboard, forced colors
References: https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html https://www.w3.org/TR/wai-aria-1.2/#aria-current https://www.w3.org/WAI/tutorials/menus/structure/ https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-current https://www.w3.org/WAI/WCAG22/Techniques/general/G128

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 site's header has four links: Home, Products, Pricing and Contact. On the pricing page, the Pricing link is bold with a bar under it, so a sighted visitor sees at a glance where they are. A screen reader user moving through the same menu hears "Home, link", "Products, link", "Pricing, link", "Contact, link". Nothing tells them which one is the page they are on. On a large site with sections and sub-menus, the same gap means they can't tell which section a page belongs to either.

## Why it fails

The bold text and the bar come from a class, `active`, that only the stylesheet reads. The menu shows a relationship, "this link is the page you are on", and WCAG 1.3.1 Info and Relationships requires that information shown by presentation is also available in the code, or in the text. Here it is only in the look. The class name means nothing to the browser, so assistive technology has nothing to pass on.

## Who is affected

Screen reader users rely on the menu to orient themselves, the way sighted visitors do. People who arrive on a page from a search result or a shared link especially need to know where they have landed. Without the mark, they have to read the heading and the content and work it out.

## What automation and AI miss

A scanner sees four valid links with names and passes them. It can't know that one link is styled as current, because a class called `active`, `selected` or `is-here` means nothing to it, and it can't check that the marker moves when the page does. AI code generators often reach for `aria-selected="true"` or `role="tab"` on the link, which belong to tabs and listboxes and are ignored or misread on a plain link. Some remove the `href` from the current link, which takes it out of the Tab order and still says nothing about it being current. Listening to the menu on two different pages is the only way to confirm that it says where you are.

## Before: the current link marked by a class

```html
<nav aria-label="Main">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/products">Products</a></li>
    <li><a href="/pricing" class="active">Pricing</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>
```

```css
nav a.active {
  font-weight: bold;
  border-bottom: 3px solid currentColor;
}
```

The `active` class gives the Pricing link its look and nothing else. A screen reader reads it as "Pricing, link", the same as the other three.

## After: aria-current on the link

```html
<nav aria-label="Main">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/products">Products</a></li>
    <li><a href="/pricing" aria-current="page">Pricing</a></li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>
```

```css
nav a[aria-current="page"] {
  font-weight: bold;
  border-bottom: 3px solid currentColor;
}
```

`aria-current="page"` tells assistive technology that this link is the page being shown, and screen readers announce it as "current page". The style now selects on the attribute instead of a class, so the look and the code come from one marker and can't point at different links. The link keeps its `href`, so it stays in the Tab order and still works as a link.

## After: hidden text, when the menu cannot take attributes

```html
<nav aria-label="Main">
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/products">Products</a></li>
    <li>
      <a href="/pricing" class="active">
        Pricing<span class="visually-hidden"> (current page)</span>
      </a>
    </li>
    <li><a href="/contact">Contact</a></li>
  </ul>
</nav>
```

```css
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
```

Some menu builders let you change a link's text but not its attributes. Text inside the link that is clipped from view becomes part of its name, so a screen reader reads "Pricing (current page), link". The words must be translated with the rest of the page, and they must be added by the same template condition that adds the `active` class. Because the visible word comes first in the name, voice control users can still say "click Pricing".

## Which option to use

Both pass 1.3.1. Use `aria-current="page"`: it does the same job with one attribute and nothing to translate, screen readers announce it in the user's own language, and styling from the attribute ties the look to the code. Use hidden text only when the menu cannot take attributes, and keep the class and the text set by the same condition.

## Implementation decisions

Other links and menus need their own choices once the main menu is right:

- Section links: when a visitor is on a page inside Products, such as a single product, the Products link is not the current page. Some sites mark it with `aria-current="true"` and a lighter style to show the current section; others leave it unmarked. Never mark it `page`.
- Several menus: a page can have a header menu, a sub-menu and a footer menu that link to the same page. Mark the link in each, so the answer is the same wherever someone reads it.
- Breadcrumbs: the last item names the current page, and takes `aria-current="page"` if it is a link. Breadcrumbs have their own guide.
- Client-side routing: in a single-page app, the router must move the attribute when the view changes. Set it from the router's current URL, not from a click handler, so a back-button move updates it too.

Keep the visual mark visible in forced colors. A bold weight and a border survive Windows contrast themes; a background colour or a change of text colour alone does not, and colour alone also fails 1.4.1. Leave the current page as a working link: people use it to reload or copy the address, and removing the `href` changes the Tab order from page to page.

## Verify the fix

1. In the code or the browser's inspector, find the current page's link in each menu, and confirm it carries `aria-current="page"` or hidden text inside the link, and that the visual style comes from the same condition.
2. With a screen reader, move to the current link and confirm it is announced as the current page.
3. Move to the other links in the same menu and confirm none of them is announced as current.
4. Go to a different page, by link and by the back button, and confirm both the look and the announcement have moved to the new page's link.
5. Turn on forced colors, such as a Windows contrast theme, and confirm the current link still looks different from the others.

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the menu or router changes.

## Limits

This is a starting pattern, not a guarantee for every menu. Screen readers word `aria-current` differently, and some say it before the link name and some after. A menu that marks the right link still leaves people lost on a site with a confusing structure; a clear page title, heading and breadcrumbs carry the rest.
