All content needs to sit inside a landmark
- Rule:
axe/region - Checks: All page content should be contained by landmarks
- WCAG: none; a best practice, not a WCAG success criterion
- Fix class:
mechanical: A fix needs no authored text or visual decision.
Who it affects
Section titled “Who it affects”- People who use a screen reader or a braille display, most of them blind.
How to fix it
Section titled “How to fix it”A heading, a paragraph or an image sits directly in <body>, beside the landmarks
Section titled “A heading, a paragraph or an image sits directly in <body>, beside the landmarks”Move it into the landmark it belongs with: the page’s own content into <main>, site-wide content into the header or the footer. A skip link before the header can stay where it is.
<header> <a href="/">Acme home</a></header><main> <h1>Orders</h1> <p>You have no open orders.</p></main>A cookie notice, an announcement bar or a promotion sits outside every landmark
Section titled “A cookie notice, an announcement bar or a promotion sits outside every landmark”Put it inside the header or the footer if it is part of the site frame. If people need to find it on its own, make it a <section> with an aria-label that names it. A notice that blocks the page belongs in a modal <dialog>.
<section aria-label="Cookie consent"> <p>We use cookies to remember your settings.</p> <button type="button">Accept cookies</button></section>A <section> or a <form> outside the landmarks has no name
Section titled “A <section> or a <form> outside the landmarks has no name”Move it into <main> or the landmark it belongs to. Neither element is a landmark without aria-label or aria-labelledby; name it only if it is a major part of the page.
Fixes that fail
Section titled “Fixes that fail”Wrapping the whole page, header and footer included, in <main>
Section titled “Wrapping the whole page, header and footer included, in <main>”axe accepts it when the header and footer have no roles, but they then stop being landmarks, so screen reader users can no longer jump to them or past them.
Wrapping stray content in role="region" without a name
Section titled “Wrapping stray content in role="region" without a name”axe counts it as a landmark, but browsers do not expose a region without a name, so screen reader users still cannot reach the content by landmark.
Adding aria-hidden="true" to the stray content
Section titled “Adding aria-hidden="true" to the stray content”It clears the rule by hiding visible content from screen reader users.
In React
Section titled “In React”The part of the fix that differs in React, in its syntax. The rest of the guidance holds.
Toasts or other messages are portaled into document.body
Section titled “Toasts or other messages are portaled into document.body”Portal them into a container with role="status" that stays mounted. axe counts a live region as inside a landmark, and screen readers announce what is added to it.
function Toasts({ messages }) { return createPortal( <div role="status"> {messages.map((message) => ( <p key={message.id}>{message.text}</p> ))} </div>, document.body, );}A dialog is portaled into document.body
Section titled “A dialog is portaled into document.body”Render it as a <dialog> opened with showModal(), or as a container with role="dialog" that manages focus itself, and name it, such as with aria-labelledby pointing at its heading. axe counts a dialog as inside a landmark.
Fixes that fail in React
Section titled “Fixes that fail in React”Mounting the toast container only while a message shows
Section titled “Mounting the toast container only while a message shows”Screen readers often miss a live region that appears together with its text. Keep the container mounted and change only what is inside it.
More on the rule
Section titled “More on the rule”axe-core’s documentation of the rule
CORA’s fix guidance adapts content from accessibility-agents, under the MIT License: see its notice.