June 15, 2020 · reala11y team
ARIA landmarks and roles: when to use native HTML5 instead
A practical guide to landmark regions (banner, nav, main, contentinfo) — when native HTML5 elements are enough, when to reach for roles, and the WordPress theme pitfalls to avoid.
Landmarks are how screen-reader users get the lay of the land. Instead of tabbing through a page link by link, they pull up a list of regions — “banner, navigation, main, complementary, contentinfo” — and jump straight to the part they want. Get your landmarks right and a blind user navigates your site the way a sighted user scans it: by skimming the structure. Get them wrong and the page is one undifferentiated wall.
The good news is that on a modern WordPress site you get most of this for free, if your theme uses real HTML5 elements. The trouble starts when it doesn’t.
The landmark regions you care about
There are eight ARIA landmark roles. In practice, five do almost all the work on a typical content site:
banner— site-wide header (logo, primary nav). One per page.navigation— a set of navigation links. You can have several.main— the primary unique content of the page. Exactly one.complementary— supporting content like a sidebar.contentinfo— site-wide footer (copyright, secondary links). One per page.
The other three — search, form, and region — are useful but situational. A search landmark around your site search box is a nice touch; region should be used sparingly, only for a genuinely significant area, and always with a label.
Native HTML5 first — roles second
Here is the single most important rule, and the one that trips up the most developers: modern HTML5 elements carry implicit landmark roles. You usually do not need to write role at all.
<header> <!-- implicit role="banner" (when not inside main/article) -->
<nav> <!-- implicit role="navigation" -->
<main> <!-- implicit role="main" -->
<aside> <!-- implicit role="complementary" -->
<footer> <!-- implicit role="contentinfo" (when not inside main/article) -->
So this is redundant and you should not write it:
<!-- Don't do this — the role duplicates what <nav> already provides -->
<nav role="navigation">
The first rule of ARIA is “don’t use ARIA if a native element will do.” Native elements come with keyboard behaviour, semantics, and landmark roles already wired up, and they survive being copy-pasted into contexts where a hand-rolled role quietly breaks.
So when do you reach for an explicit role? Two cases:
- The element isn’t semantic. If a theme builds its header from
<div class="site-header">, you can patch it withrole="banner"rather than rewriting the markup. Better to fix the element, but the role is a valid stopgap. - The implicit role doesn’t apply in context. A
<header>inside an<article>or<main>is not abanner— it’s just a section header. If you specifically need a banner there (you almost never do), you’d add the role explicitly.
Labelling repeated landmarks
If you have more than one of the same landmark — and most sites have two or three <nav> elements (primary menu, footer menu, maybe a breadcrumb) — a screen reader announces each as just “navigation,” which is useless. Distinguish them with an accessible name:
<nav aria-label="Primary">…</nav>
<nav aria-label="Footer">…</nav>
Use aria-label for a short invisible name, or aria-labelledby to point at a visible heading. Don’t include the word “navigation” in the label — the screen reader already says it, so “Primary navigation navigation” is what you’d get.
WordPress theme pitfalls
This is where real sites fall down. Common patterns we see:
- No
<main>at all. Many older themes wrap content in<div id="content">and never declare a main landmark. Screen-reader users lose their single most important jump target. The fix is<main id="main">around the content area in the template. - Two banners or two contentinfos. A header partial included twice, or a page builder that injects its own header, can produce duplicate
bannerregions. There must be only one of each per page. - Page builders that emit
<div>soup. Elementor, Divi, and similar tools historically rendered everything as nested<div>s with no landmark semantics. Newer versions are better, but check the rendered output, not the editor. - Block themes are usually better. WordPress block themes (the Twenty Twenty-Two generation onward) use template parts that map to
<header>,<main>, and<footer>out of the box — one reason they tend to land closer to the mark on structure.
The catch with all of these is that the problem lives in theme output, not your post content. You can write perfect content and still ship a page with no main landmark because the template never declared one.
Test it in five minutes
You do not need a screen reader to sanity-check landmarks. Install a browser extension like axe DevTools or the Landmarks extension, load a page, and look at the regions it reports. You’re checking for: exactly one main, exactly one banner, exactly one contentinfo, and a sensible label on every repeated nav. Then, ideally, confirm with an actual screen reader — pull up its landmarks list (in NVDA, press D to cycle regions) and make sure you can reach the content in one move.
reala11y’s scanner flags a missing main landmark (rule R013) as part of a WCAG 1.3.1 pass, because that signal is right there in the markup. See how it works for what it inspects.
The honest takeaway
Landmarks are cheap to get right and expensive to ignore — a handful of semantic elements that turn a flat page into something a screen-reader user can navigate by structure. Reach for native HTML5 elements first; add a role only when the element isn’t semantic or its implicit role doesn’t fit. A scanner can confirm the regions exist and that you haven’t doubled up, and that’s genuinely useful — but automated tooling only catches roughly 30–40% of WCAG issues by criteria, and whether your landmarks describe a sensible structure is a judgement only a person can make. Fix the markup, then navigate it yourself with a screen reader’s landmark list. That combination moves you toward WCAG 2.2 AA conformance — which is the honest goal; no tool makes the claim for you.