Search topics
Missing or misplaced landmarks, and content outside them
A bookshop's pages are built from divs, or wrap the header, a second main and the footer in one main, so a screen reader's landmark list is empty, or says almost the whole page is the main content.
<div id="content"> The problem
Screen reader users can't jump to the content, the menu or the footer by landmark, and miss whatever sits outside every landmark.
A bookshop's pages share one layout. A thin strip at the top says "Free delivery on orders over $30". Below it are the logo, Harbour Books, and a menu of four links, then the page's own content, here a list of new releases, and a footer with Contact and Returns. A screen reader user who wants the new releases does what they do on any shop: open the landmark list, which screen readers offer so people can jump to an area of the page, or press the key that moves from landmark to landmark. On these pages the list is empty and the key finds nothing, so unless they jump by heading, they read from the top, through the strip, the logo and every menu link.
A redesign then moves the pages into a new app layout, and the list now reads "main", "navigation", "main". The first main is almost the whole page, so choosing it lands on the logo. The second is the content. Banner and content information, the header and footer, are missing from the list, and the delivery strip is in no landmark at all, so moving landmark by landmark passes it by.
The page shows four areas, and 1.3.1 needs structure that people see to be available in code too. HTML has an element for each of these areas: a header at the top level of the page is the banner landmark, nav is a navigation landmark, main is the main content, and a footer at the top level is the content information landmark. WCAG techniques H101 and ARIA11 use them to meet 1.3.1. The first version uses a div for all four, so the code exposes none of them.
The second version has landmarks, but in the wrong places:
- The layout wraps everything in a
main, so the main landmark starts at the logo and claims the header and footer as content. - A
headerorfooterinsidemain,article,aside,navorsectionis not a banner or content information landmark, so the site's header and footer stop being landmarks at all. - The page adds its own
maininside the layout's. HTML allows onemainthat isn't hidden, with no ancestors other thanhtml,body,div, a form with no accessible name or autonomous custom elements, but both elements are still exposed as main, so a screen reader lists two. - The delivery strip sits above the outer
main, in no landmark.
WCAG lists landmarks as sufficient techniques, not requirements, and no WCAG failure technique names a page without them, so an auditor may pass a page whose headings carry the same structure. Here nothing else does: the menu and the footer have no headings, and the only heading is the content's own.
Both versions look exactly right, so nobody who reads the page by sight notices. The failure is in the markup, and it repeats on every page that shares the layout.
2 of 10 groups affected
- No vision (affected)
- Low vision (affected)
- Colour vision (not affected)
- No hearing (not affected)
- Hard of hearing (not affected)
- No speech (not affected)
- Motor (not affected)
- Reach, strength (not affected)
- Cognitive (not affected)
- Seizures (not affected)
- Without vision Screen reader users open the landmark list, or press a landmark key, to go straight to the content, the menu or the footer. On a page of divs the list is empty, and where one main wraps almost the whole page, jumping to main lands on the site header.
- Limited vision People who use a screen reader alongside magnification may move by landmarks instead of panning across a wide page, and miss a notice that sits outside every landmark, such as a delivery offer above the header.
axe has a rule for most of this: region for content outside every landmark, landmark-one-main for a page with no main, landmark-no-duplicate-main and landmark-main-is-top-level for the second, nested main, and four more for a banner or content information landmark used twice or placed inside another landmark. axe classes them all as best practice, so audits that run only the WCAG rules never report them. None of them sees the header and footer inside main: a header there is meant to be an ordinary header, as an article's is, so axe leaves it alone. This audit sends that case to a person: a page with no banner, or no content information, whose first header or footer sits inside main or a sectioning element is raised for review. Quick fixes can add a landmark rather than move one. They put role="main" on yet another wrapper, role="banner" on the header that is still inside main, where it becomes a banner inside the main content, or a label on every section, which fills the landmark list with regions nobody wants. Whether each area sits in the right landmark, and whether a nested header is the site's or an article's, is something a person has to judge against the page.
Try it
Use the landmark list to jump to the new releases.
The list shows the landmarks a screen reader finds on this bookshop page. Choose an entry to jump to it. Turn on Show landmarks to see which part of the page each one covers. In Broken 2, where does the first main take you?
Broken Can you fix this?
Screen reader’s landmarks list:
(none)
The fix
Put every area of the page in a landmark, with the header, main and footer side by side at the top level.
- 1Each page has one main landmark, at the top level, that holds the content and nothing else.
- 2The site header and footer are banner and contentinfo landmarks, once each, outside main.
- 3Everything on the page sits in a landmark, strips above the header and notices after the footer included.
A page built from divs
<div class="top-bar">Free delivery on orders over $30</div><div class="header"> <a href="/" class="logo">Harbour Books</a> <div class="menu"> <a href="/fiction">Fiction</a> <a href="/non-fiction">Non-fiction</a> <a href="/children">Children</a> <a href="/events">Events</a> </div></div><div id="content"> <h1>New releases</h1> <ul class="books">…</ul></div><div class="footer"> <a href="/contact">Contact</a> <a href="/returns">Returns</a></div>Header, nav, main and footer elements
<div class="layout"> <header> <div class="top-bar">Free delivery on orders over $30</div> <a href="/" class="logo">Harbour Books</a> <nav> <a href="/fiction">Fiction</a> <a href="/non-fiction">Non-fiction</a> <a href="/children">Children</a> <a href="/events">Events</a> </nav> </header> <main id="content"> <h1>New releases</h1> <ul class="books">…</ul> </main> <footer> <a href="/contact">Contact</a> <a href="/returns">Returns</a> </footer></div>Why this fix: Use native HTML first
Every area is a div, so the page has no landmarks: the landmark list is empty, and everything on the page sits outside one.
The header, the content and the footer sit side by side in a div, which is allowed around main, and there is one main. The strip moves inside the header, where it is part of the banner. The landmark list now reads "banner", "navigation", "main", "content information", in the order the page shows them, and nothing sits outside a landmark.
Both give screen readers the same four landmarks and meet 1.3.1. Use the elements wherever you can change the template: they do the same job with no attributes to keep in step, a header or footer that later ends up inside main stops being a landmark instead of becoming one in the wrong place, and scripts and tools that read the HTML rather than the accessibility tree see them too. Keep the roles for a template whose elements you can't change, such as a theme whose styles and scripts select div.header, and switch to the elements when you can.
Let one layout own the page's shell. The root layout renders the header, one main and the footer side by side, and each page renders its content inside that main, in a div or section of its own, never another main. In a single-page app, keep the main in place on a route change and replace what is inside it. A main with the hidden attribute doesn't count, so an app that keeps several views in the page can give each one a main as long as only one is shown at a time.
Find a landmark for everything the layout adds around the content. Each kind belongs somewhere.
- A strip or promotion above the site header goes inside the
header, as part of the banner. - A cookie notice or a newsletter bar appended after the footer becomes a
sectionwith a name (<section aria-label="Cookie notice">), which makes it a region, or a dialog if it is one. - A third-party chat or feedback button usually injects its own markup at the end of
body. Check where it lands, and, if it is outside every landmark, ask the vendor or wrap the container you load it into.
A skip link can stay before the header, outside every landmark: that is where people expect it, and axe allows it there.
An article's own header and footer are right inside it. A product card, a blog post or a review can have a header with its title and a footer with its date; inside article or main they are not banners, and they shouldn't be. Don't give them role="banner" or role="contentinfo".
Name landmarks only when they need it. One banner, one main and one content information landmark need no name. When a role appears more than once, such as two nav elements, each needs its own name, as navigation landmarks that all sound the same explains. A section becomes a region landmark only when it has a name, so name the few that people would want to jump to and let headings divide the rest.
Current browsers map these elements to their roles, so <main role="main"> and <nav role="navigation"> repeat what the element already says. Leave the extra role out.
Fixing this with an AI coding assistant? Get this guide as Markdown, or get every guide in your coding agent.
Verify the fix
4 checks, no mouse.
Test with: Screen reader
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat whenever the layout or a third-party widget changes.
Limits
This is a starting pattern, not a guarantee for every application. Paths, class names and the … in the lists are placeholders. Screen readers word the landmark list differently ("content info" or "content information", with "landmark" or "region" after it, or neither), so listen for the areas rather than the exact phrasing. Landmarks give screen reader users a way past the header, and WCAG 2.4.1 accepts them as one, but sighted keyboard users have no landmark keys, so for them the page should still have a skip link past repeated navigation for them. This guide covers whether the page has the right landmarks in the right places. It doesn't cover naming repeated landmarks, for which see navigation landmarks that all sound the same, or the headings inside them, for which see headings chosen by size, not by structure. Test the complete journey with your target assistive technology.
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.
References
- WCAG Understanding: info-and-relationships (opens in a new tab)
- WCAG Technique H101 (opens in a new tab)
- WCAG Technique ARIA11 (opens in a new tab)
- ARIA APG: landmark-regions (opens in a new tab)
- html.spec.whatwg.org: grouping-content (opens in a new tab)
- w3.org: html-aam-1.0 (opens in a new tab)
- developer.mozilla.org: header (opens in a new tab)
- dequeuniversity.com: region (opens in a new tab)
- dequeuniversity.com: landmark-one-main (opens in a new tab)
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.