Guias de acessibilidade para cego
Aprenda como identificar e corrigir problemas de acessibilidade comuns sinalizados pelo Axe Core — para que suas páginas sejam inclusivas e utilizáveis por todos. Consulte também o nosso Guias de validação HTML.
Images are a fundamental part of web content, but they are inherently visual. Screen readers cannot interpret the pixels of an image — they rely entirely on a text alternative to describe the image’s content and purpose to the user. Without alternative text, a screen reader may read out the image’s file name (e.g., “IMG_20230415_093012.jpg”), which is meaningless and confusing. In the worst case, the image is silently skipped, and the user misses critical information.
This rule primarily affects people who are blind or deafblind, who depend on screen readers or braille displays to access content. Users with low vision who rely on text magnification or high-contrast modes can also benefit from well-written alternative text.
Why This Matters
This rule maps to WCAG 2.2 Success Criterion 1.1.1: Non-text Content (Level A), which requires that all non-text content presented to the user has a text alternative that serves an equivalent purpose. It is also required by Section 508 and EN 301 549. Because it is a Level A requirement, it represents the absolute minimum baseline for accessibility — failing it means your content is fundamentally inaccessible to many users.
How to Provide Alternative Text
There are three main techniques for giving an image accessible alternative text:
-
The
altattribute — the most common and preferred method for<img>elements. -
The
aria-labelattribute — provides an accessible name directly on the element. -
The
aria-labelledbyattribute — points to theidof another element that contains the descriptive text.
Writing Good Alt Text
When writing alternative text, consider these questions:
- Why is this image here? What role does it play in the content?
- What information does it convey? What would a sighted user take away from it?
- If you removed the image, what words would replace it to preserve the same meaning?
Keep alt text concise and descriptive. Avoid phrases like “image of” or “picture of” — screen readers already announce the element as an image. Don’t use the file name as alt text. Focus on the image’s purpose and meaning, not a pixel-by-pixel description.
Handling Decorative Images
Not every image carries meaning. Decorative images — such as visual separators, background flourishes, or images whose content is fully described in surrounding text — should be hidden from assistive technology. To do this, use an empty alt attribute: alt="".
Do not omit the alt attribute entirely. If alt is missing, screen readers will often fall back to reading the file name, which creates a worse experience than having no announcement at all. An empty alt="" explicitly tells the screen reader to skip the image.
You can also use role="presentation" or role="none" to mark an image as decorative, but an empty alt attribute is simpler and more widely supported.
Examples
Incorrect: Missing Alt Text
The alt attribute is completely absent. A screen reader may announce the file name instead.
<img src="team-photo.jpg">
Incorrect: Unhelpful Alt Text
The alt text contains the file name rather than a meaningful description.
<img src="chart-q3.png" alt="chart-q3.png">
Correct: Descriptive Alt Text Using the alt Attribute
<img src="team-photo.jpg" alt="The engineering team gathered around a whiteboard during a planning session">
Correct: Alt Text Using aria-label
<img src="revenue-chart.png" aria-label="Bar chart showing quarterly revenue increasing from $2M in Q1 to $3.5M in Q4">
Correct: Alt Text Using aria-labelledby
<p id="chart-desc">Bar chart showing quarterly revenue growth from Q1 to Q4 2024.</p>
<img src="revenue-chart.png" aria-labelledby="chart-desc">
Correct: Decorative Image with Empty Alt
This separator line serves no informational purpose and should be hidden from screen readers.
<img src="decorative-line.svg" alt="">
Correct: Decorative Image Using role="presentation"
<img src="decorative-swirl.png" role="presentation">
What This Rule Checks
This axe-core rule (image-alt) inspects every <img> element on the page and verifies that it has an accessible text alternative. Specifically, it checks that each <img> has at least one of the following:
-
A non-empty
altattribute -
An
aria-labelattribute -
An
aria-labelledbyattribute that references a valid element -
An empty
alt=""(orrole="presentation"/role="none") to indicate the image is decorative
If none of these conditions are met, the rule flags the image as a critical accessibility violation.
Why this is a problem
Screen readers process both the alternative text of an image and any visible text surrounding it. When these are identical, users hear something like “Home Page Home Page” — the same phrase spoken back-to-back. This redundancy is disorienting, slows users down, and adds no value. In some cases it can even be misleading, causing users to think there are two separate elements when there is only one.
This issue primarily affects blind and deafblind users who rely on screen readers to interpret page content. It is flagged as a Deque best practice and aligns with the principles behind WCAG Success Criterion 1.1.1 (Non-text Content), which requires that non-text content has a text alternative that serves an equivalent purpose — not a duplicated one.
How to fix it
The fix depends on the context:
-
Decorative or redundant images inside links or buttons: If visible text already describes the purpose, set
alt=""on the image. The image becomes decorative, and the screen reader reads only the visible text. -
Images that add unique information: If the image conveys something the adjacent text does not, write
alttext that describes only the additional information — don’t repeat what’s already there. -
Image buttons (
<input type="image">): Thealtattribute serves as the button’s label. Make sure it clearly describes the action (e.g., “Submit,” “Search”) and does not duplicate text placed next to the button.
Tips for writing good alternative text
- Describe the purpose or action, not the visual appearance of the image.
- Ask yourself: “If I removed this image, what words would I need to convey the same information?”
- Avoid filler words like “image of,” “picture of,” or file names — they add noise without value.
- Keep it concise and meaningful.
Examples
Incorrect: alt text duplicates adjacent link text
The screen reader announces “Home Page Home Page” because both the alt attribute and the visible text say the same thing.
<a href="index.html">
<img src="home-icon.png" alt="Home Page" width="24" height="25">
Home Page
</a>
Correct: empty alt on a redundant image inside a link
Since the visible text “Home Page” already describes the link, the icon is marked as decorative with alt="". The screen reader announces “Home Page” once.
<a href="index.html">
<img src="home-icon.png" alt="" width="24" height="25">
Home Page
</a>
Incorrect: button text duplicated next to an image button
The word “Search” appears both as the alt text on the image button and as adjacent visible text, causing duplication.
<input type="image" src="search.png" alt="Search">
<span>Search</span>
Correct: remove the redundant adjacent text
When using an image button, let the alt attribute be the sole label and remove the duplicate text.
<input type="image" src="search.png" alt="Search">
Correct: image adds unique information alongside text
If the image conveys something the text does not, write alt text that captures only the unique information.
<a href="report.html">
<img src="chart.png" alt="Bar chart showing 40% increase in Q3" width="80" height="60">
Quarterly Report
</a>
Here, the visible text says “Quarterly Report” while the image’s alt text describes what the chart actually shows — no duplication, and both pieces of information are useful.
Every interactive control on a page needs an accessible name so that assistive technologies can announce it to users. For <input> elements with type="button", type="submit", or type="reset", the accessible name typically comes from the value attribute. While <input type="submit"> and <input type="reset"> have default browser-provided labels (“Submit” and “Reset”), <input type="button"> has no default — it renders as an empty, unlabeled button if no name is provided.
This issue critically affects blind and deafblind users who rely on screen readers. When a screen reader encounters an input button without discernible text, it may announce something like “button” with no indication of what the button does. This makes it impossible to navigate forms, submit data, or perform actions confidently. Sighted users can often infer a button’s purpose from visual context, but screen reader users depend entirely on the programmatic accessible name.
Related WCAG Success Criteria
This rule maps to WCAG 2.2 Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that all user interface components have a name that can be programmatically determined. It also relates to Section 508 requirements that every non-text element must have a text equivalent, and EN 301 549 Section 9.4.1.2.
How to Fix It
There are several ways to give an input button a discernible accessible name:
-
valueattribute — The most straightforward approach. Setvalueto descriptive text that communicates the button’s purpose. -
aria-labelattribute — Provides an accessible name directly. Useful when you need the accessible name to differ from the visible text, or whenvaluecannot be used. -
aria-labelledbyattribute — References another element’sidwhose text content becomes the accessible name. The referenced element must exist and contain text. -
titleattribute — Acts as a fallback accessible name. However,titleis less reliable because it is not consistently exposed by all assistive technologies and only appears as a tooltip on hover, making it inaccessible to keyboard and touch users. Prefervalueoraria-labelinstead.
For <input type="submit"> and <input type="reset">, browsers provide default labels, so they pass without an explicit value. However, if you set value="" (an empty string), you override the default and create an empty accessible name, which fails.
Examples
Incorrect: Input button with no accessible name
<form action="/search">
<input type="button" id="go" />
</form>
This button has no value, aria-label, aria-labelledby, or title. A screen reader will announce it as just “button” with no context.
Incorrect: Empty aria-label
<form action="/search">
<input type="button" aria-label="" />
</form>
An empty aria-label does not provide a discernible name.
Incorrect: aria-labelledby referencing a nonexistent or empty element
<form action="/search">
<input type="button" aria-labelledby="nonexistent" />
</form>
<form action="/search">
<input type="button" aria-labelledby="empty-label" />
<div id="empty-label"></div>
</form>
If the referenced element doesn’t exist or has no text content, the button has no accessible name.
Incorrect: Submit or reset with an empty value
<form action="/search">
<input type="submit" value="" />
<input type="reset" value="" />
</form>
Setting value to an empty string overrides the browser’s default label, leaving the button unnamed.
Correct: Using the value attribute
<form action="/search">
<input type="button" value="Search" />
</form>
Correct: Using aria-label
<form action="/search">
<input type="button" aria-label="Search" />
</form>
Correct: Using aria-labelledby
<form action="/search">
<input type="button" aria-labelledby="btn-label" />
<span id="btn-label">Search</span>
</form>
Correct: Submit and reset with default or explicit values
<form action="/search">
<input type="submit" />
<input type="reset" />
<input type="submit" value="Send Form" />
<input type="reset" value="Clear All Fields" />
</form>
The first two rely on the browser’s built-in default labels (“Submit” and “Reset”). The last two provide custom, more descriptive labels through the value attribute. Both approaches are valid, though explicit descriptive labels are generally preferred for clarity.
An <input type="image"> element renders an image that functions as a submit button. Unlike standard <input type="submit"> buttons that display their value attribute as visible text, image buttons rely entirely on their visual appearance to communicate purpose. This means assistive technologies have no way to determine the button’s function unless you explicitly provide alternative text.
This is a critical accessibility barrier for several groups of users. Blind and deafblind users who rely on screen readers will hear something generic like “button” or, worse, the image file name (e.g., “btn_submit_v2.png”), which provides no useful information. Users with low vision who use screen magnifiers in combination with screen readers are similarly affected. Without a clear accessible name, these users cannot confidently interact with forms.
This rule relates to two WCAG success criteria at Level A — the minimum conformance level:
- WCAG 1.1.1 (Non-text Content): All non-text content must have a text alternative that serves the equivalent purpose. An image button is non-text content, so it needs alternative text.
- WCAG 4.1.2 (Name, Role, Value): All user interface components must have a programmatically determinable name. Buttons must expose their name to assistive technologies.
This requirement is also mandated by Section 508, EN 301 549, and the Trusted Tester guidelines.
How to fix it
Provide a non-empty accessible name for every <input type="image"> element using one of these methods:
-
altattribute (preferred): Add analtattribute that describes the button’s action. This is the most straightforward and widely supported approach. -
aria-labelattribute: Set anaria-labelwith a concise description of the button’s action. -
aria-labelledbyattribute: Reference theidof another visible element that describes the button’s action.
Writing effective alternative text
The alternative text for an image button should describe the action the button performs, not the image itself. Ask yourself: “What happens when the user clicks this button?” The answer is your alternative text.
- ✅ “Submit”, “Search”, “Add to cart”, “Log in”
- ❌ “Green arrow icon”, “button.png”, “click here”
Avoid filler words like “image of” or “button” — assistive technologies already announce the element’s role as a button.
Important: Simply placing text next to the image button in the HTML is not sufficient. Screen readers need a programmatically associated label, not visually adjacent text. Nearby text cannot be reliably determined as the button’s label by assistive technologies.
Examples
Incorrect: missing alternative text
The image button has no alt, aria-label, or aria-labelledby attribute. A screen reader might announce this as “submit.png button” or just “button.”
<form action="/search">
<label for="query">Search</label>
<input type="text" id="query" name="q">
<input type="image" src="search-icon.png">
</form>
Incorrect: empty alt attribute
An empty alt attribute tells assistive technologies to ignore the element, effectively hiding the button entirely.
<input type="image" src="search-icon.png" alt="">
Correct: using the alt attribute
<form action="/search">
<label for="query">Search</label>
<input type="text" id="query" name="q">
<input type="image" src="search-icon.png" alt="Search">
</form>
Correct: using aria-label
<input type="image" src="submit-arrow.png" aria-label="Submit order">
Correct: using aria-labelledby
The aria-labelledby attribute points to the id of a visible element. Make sure the referenced element exists and is not hidden with display: none or aria-hidden="true".
<h2 id="checkout-heading">Complete your purchase</h2>
<form action="/checkout">
<!-- form fields -->
<input type="image" src="checkout-btn.png" aria-labelledby="checkout-heading">
</form>
What the rule checks
This rule verifies that every <input type="image"> element has a discoverable accessible name. It fails if the element has no alt, aria-label, or aria-labelledby attribute, or if those attributes are empty or resolve to an empty string.
When an interactive element displays visible text — like a button saying “Submit” — users naturally expect that text to be the element’s name. However, developers sometimes use aria-label or aria-labelledby to set an accessible name that differs from the visible text. This creates a disconnect: what sighted users see and what assistive technologies announce become two different things.
This is a serious accessibility problem that primarily affects speech input users. These users interact with web pages by speaking the names of controls they see on screen. If someone sees a link labeled “Next Page” and says “click Next Page,” but the accessible name is actually “OK,” the speech command fails. The user has no way to know the correct programmatic name, leading to frustration and an inability to use the interface.
This issue also affects screen reader users and users with cognitive disabilities. When a screen reader announces a name that doesn’t match the visible label, it creates confusion — the user may not be sure they’re focused on the right element. For users with cognitive disabilities who rely on consistent, predictable interfaces, this mismatch adds unnecessary complexity.
This rule checks compliance with WCAG 2.1 Success Criterion 2.5.3: Label in Name (Level A). This criterion requires that when a user interface component has a visible text label, the accessible name must contain that visible text. The intent is to ensure that the words users see on screen can be used to interact with the component, regardless of input method.
The rule applies to elements that meet all three conditions:
-
The element has a widget role that supports name from content — specifically:
button,checkbox,gridcell,link,menuitem,menuitemcheckbox,menuitemradio,option,radio,searchbox,switch,tab, ortreeitem. - The element has visible text content.
-
The element has an
aria-labeloraria-labelledbyattribute that overrides the default accessible name.
When evaluating the match, leading and trailing whitespace is ignored, and the comparison is case-insensitive. The complete visible text must either match the accessible name exactly or be fully contained within it.
How to Fix
To resolve this issue:
-
Make the accessible name include the full visible text. If the element’s visible text is “Next Page,” the
aria-labelmust contain “Next Page” — not just part of it, and not something completely different. - Start the accessible name with the visible text. While not strictly required, it’s best practice. This helps speech input users who may only speak the beginning of a label.
-
Consider removing the
aria-labelentirely. If the visible text alone is a sufficient accessible name, you may not need an override at all. The simplest fix is often to let the element derive its name from its content naturally.
Examples
Failing: Accessible name doesn’t match visible text
The visible text says “Next” but the accessible name is “OK”:
<div role="link" aria-label="OK">Next</div>
Failing: Accessible name only contains part of the visible text
The visible text is “The full label” but the accessible name is “the full,” which doesn’t include the complete visible text:
<button aria-label="the full">The full label</button>
Passing: Accessible name matches visible text
The aria-label matches the visible text (trailing whitespace and case differences are ignored):
<div role="link" aria-label="Next Page">next page</div>
Passing: Accessible name contains the full visible text
The visible text “Next Page” is fully contained within the accessible name:
<button aria-label="Next Page in the list">Next Page</button>
Passing: No aria-label override needed
When the visible text is already a good accessible name, simply omit the aria-label:
<button>Next Page</button>
Passing: aria-labelledby references text that includes the visible content
<span id="btn-label">Search the full catalog</span>
<button aria-labelledby="btn-label">Search</button>
Here, the visible text “Search” is contained within the accessible name “Search the full catalog,” so the rule passes. The accessible name begins with the visible label, which is ideal for speech input users.
The title and aria-describedby attributes serve a supplementary role in accessibility — they convey hints, tooltips, or additional descriptions. However, they are not treated as primary labels by accessibility APIs. When a screen reader encounters a form field that has only a title or aria-describedby attribute and no proper label, it may present the text as advisory information rather than as the field’s name. This makes it difficult or impossible for users to understand what input is expected.
This issue primarily affects users who are blind, deafblind, or who rely on assistive technologies such as screen readers. It can also impact users with mobility impairments who use voice control software, since voice control often relies on visible labels to target form elements. A missing visible label also hurts sighted users who may not see a tooltip until they hover over the element.
This rule is classified as a Deque Best Practice and aligns with the broader intent of WCAG Success Criterion 1.3.1 (Info and Relationships), which requires that information and relationships conveyed visually are also available programmatically, and SC 2.4.6 (Labels or Instructions), which requires that labels describe the purpose of form controls. While title and aria-describedby do expose some text, they do not fulfill the requirement for a reliable, programmatically determinable label.
How to Fix It
Every form control needs a proper accessible name. You can provide one using any of these methods:
-
Explicit
<label>element — Associate a<label>with the form control using matchingforandidattributes. This is the most reliable and widely supported approach. -
Implicit
<label>element — Wrap the form control inside a<label>element. This works in most assistive technologies but has inconsistent support in some combinations (e.g., JAWS with<select>menus). -
aria-labelledby— Reference visible text elsewhere on the page by itsid. Useful for complex labeling scenarios. -
aria-label— Apply an invisible label directly to the element. Use this only when a visible label is truly not feasible.
In most cases, an explicit <label> is the best choice. It creates a clear association, provides a larger click/tap target, and is universally supported.
Examples
Incorrect: Using Only title
The title attribute provides a tooltip on hover but does not create a proper accessible label.
<input type="text" title="Enter your email address">
Incorrect: Using Only aria-describedby
The aria-describedby attribute provides a description, not a label. Screen readers may announce this text differently or skip it in certain contexts.
<p id="email-hint">Enter your email address</p>
<input type="text" aria-describedby="email-hint">
Correct: Explicit <label> Element
This is the recommended approach. The for attribute on the <label> matches the id on the input, creating an unambiguous association.
<label for="email">Email Address</label>
<input type="text" id="email" name="email">
You can still use title or aria-describedby for supplementary hints alongside a proper label:
<label for="email">Email Address</label>
<input type="text" id="email" name="email" title="e.g., user@example.com">
Correct: Implicit <label> Element
Wrapping the input inside the <label> creates an implicit association. This works for most assistive technologies but is less reliable than explicit labels.
<label>
Email Address
<input type="text" name="email">
</label>
Correct: Using aria-labelledby
Reference visible text on the page by its id. This is useful when the labeling structure is complex, such as data tables with form controls, or when multiple elements share a label.
<p id="email-label">Email Address</p>
<input type="text" aria-labelledby="email-label">
Correct: Using aria-label
This provides a label that is invisible on screen. Use it only when a visible label cannot be provided, such as a search field with a clearly identifiable search icon and button.
<input type="text" aria-label="Search">
<button type="submit">Search</button>
Note: Because aria-label is not visible, sighted users get no label text. Prefer a visible <label> whenever possible.
Every form element — such as text inputs, checkboxes, radio buttons, and select menus — must have a programmatically associated label so that assistive technologies can identify and announce the purpose of each field. Without these labels, screen reader users cannot determine what information is expected, and users with motor impairments lose the benefit of a larger clickable target area that a properly associated <label> provides.
Why This Matters
When a form element lacks a programmatic label, screen readers either announce it generically (e.g., “edit text” or “checkbox”) or skip meaningful context entirely. This leaves blind, low-vision, and deafblind users unable to understand what data a field expects or what option a checkbox represents. They must guess based on surrounding content, which is unreliable and error-prone.
Labels also benefit users with motor impairments. When a <label> element is properly associated with an input, clicking the label text activates or focuses the associated control. This creates a larger click target, which is especially helpful for people with limited dexterity.
Sighted users often rely on visual proximity to infer a field’s purpose, but assistive technologies need an explicit programmatic relationship between the label text and the form control to convey the same information.
Relevant Standards
This rule maps to WCAG Success Criterion 4.1.2: Name, Role, Value (Level A), which requires that all user interface components have an accessible name that can be programmatically determined. It applies across WCAG 2.0, 2.1, and 2.2, as well as Section 508 (§1194.22(n)), EN 301 549 (9.4.1.2), and Trusted Tester guidelines. The user impact is considered critical.
How to Fix It
There are several ways to associate a label with a form element. Use the approach that best fits your situation, listed here from most recommended to least recommended.
1. Explicit <label> with for and id (Recommended)
The most common and reliable method is to use a <label> element whose for attribute matches the id of the form control. This creates an unambiguous programmatic association.
2. Implicit <label> (Wrapping)
Wrap the form control inside a <label> element. The association is implied by the parent-child relationship.
3. aria-label
Use aria-label when the field’s purpose is conveyed visually through an icon or layout rather than visible text. This creates an invisible label that only screen readers announce.
4. aria-labelledby
Use aria-labelledby when the label text already exists elsewhere on the page, or when you need to combine multiple pieces of text into a single label. Reference one or more element id values.
5. placeholder (Not Recommended)
A placeholder attribute can technically provide an accessible name, but it disappears once the user begins typing, removing the visible label. This creates usability problems for everyone and is not a recommended approach.
General Tips
-
Ensure all
idvalues are unique on the page. - Make label text descriptive and meaningful when read aloud in isolation.
-
Remember that buttons (
<button>,<input type="submit">, etc.) are self-labeling through their text content orvalueattribute and do not need a separate<label>. -
Hidden inputs (
<input type="hidden">) do not need labels since they are not presented to users.
Examples
Incorrect: Input without a label
<div>First name:</div>
<input type="text" id="firstname">
The <div> text is visually near the input, but there is no programmatic relationship. A screen reader will announce only “edit text” with no context.
Correct: Explicit label with for and id
<label for="firstname">First name:</label>
<input type="text" id="firstname">
Correct: Implicit label by wrapping
<label>
First name:
<input type="text">
</label>
Correct: aria-label for visually implied fields
<input type="text" aria-label="Search">
<button type="submit">🔍</button>
Correct: aria-labelledby referencing existing text
<div id="temp-label">Temperature</div>
<div id="high-label">High:</div>
<div id="low-label">Low:</div>
<input type="text" aria-labelledby="temp-label high-label">
<input type="text" aria-labelledby="temp-label low-label">
The first input is announced as “Temperature High:” and the second as “Temperature Low:”, combining the referenced text in order.
Incorrect: Relying only on placeholder
<input type="text" placeholder="Enter your email">
While this technically provides an accessible name, the visible hint disappears when the user starts typing, making it difficult to verify the field’s purpose. Always prefer a persistent visible label.
Correct: Visible label with supplementary placeholder
<label for="email">Email address</label>
<input type="text" id="email" placeholder="name@example.com">
Incorrect: Checkbox without a label
<input type="checkbox" id="terms">
I agree to the terms and conditions
The text is adjacent but not associated with the checkbox.
Correct: Labeled checkbox
<input type="checkbox" id="terms">
<label for="terms">I agree to the terms and conditions</label>
Landmarks provide a structural map of a page’s layout that screen reader users rely on to quickly jump between major sections — the header, navigation, main content, footer, and so on. The banner landmark specifically represents the site-wide header area, typically containing the logo, site title, and primary navigation.
When a banner landmark is nested inside another landmark (for example, inside a <main> element or a <nav> element), screen readers present it as a subordinate section rather than a top-level region of the page. This breaks the expected page structure and makes it significantly harder for blind and deafblind users to orient themselves. Instead of finding the banner at the top level of the landmark tree, they encounter it buried within another region, which undermines the purpose of landmarks entirely.
This rule is a Deque best practice for accessible landmark structure. While it doesn’t map to a specific WCAG success criterion, it directly supports the principles behind WCAG 1.3.1 Info and Relationships (ensuring structural information is programmatically determinable) and WCAG 2.4.1 Bypass Blocks (providing mechanisms to skip repeated content).
How to Fix It
-
Identify the banner landmark — Look for any
<header>element that is a direct child of<body>(which automatically has thebannerrole) or any element withrole="banner". -
Check if it’s nested — Determine whether the banner is contained inside another landmark element such as
<main>,<nav>,<aside>,<section>(with an accessible name), or any element with an ARIA landmark role. -
Move it to the top level — Restructure your HTML so the banner landmark is a direct child of
<body>, outside of any other landmark.
Keep in mind that a <header> element only has the implicit banner role when it is not nested inside <article>, <aside>, <main>, <nav>, or <section>. When nested inside those elements, <header> has no implicit landmark role and won’t trigger this rule. However, if you explicitly add role="banner" to a nested element, or if your page structure inadvertently places the top-level <header> inside another landmark, the issue will be flagged.
Examples
Incorrect: Banner Nested Inside Main Landmark
In this example, the <header> with role="banner" is placed inside <main>, making it a nested landmark.
<body>
<main>
<header role="banner">
<h1>My Website</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<p>Main content goes here.</p>
</main>
</body>
Incorrect: Banner Inside a Navigation Landmark
<body>
<nav aria-label="Site navigation">
<div role="banner">
<img src="logo.png" alt="Company Logo">
</div>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<main>
<p>Main content goes here.</p>
</main>
</body>
Correct: Banner as a Top-Level Landmark
The <header> is a direct child of <body>, making it a proper top-level banner landmark.
<body>
<header>
<h1>My Website</h1>
<nav aria-label="Primary">
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<main>
<p>Main content goes here.</p>
</main>
<footer>
<p>© 2024 My Website</p>
</footer>
</body>
Correct: Using role="banner" at the Top Level
<body>
<div role="banner">
<h1>My Website</h1>
<nav aria-label="Primary">
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</div>
<main>
<p>Main content goes here.</p>
</main>
</body>
Note that using the native <header> element is preferred over role="banner" on a <div>, since native HTML semantics are more robust and widely supported.
Landmark regions are structural areas of a page — like <main>, <nav>, <header>, <footer>, and <aside> — that help assistive technology users understand the layout and quickly navigate between sections. Screen readers provide shortcut keys that let users jump directly to these landmarks, making it easy to skip to the content they need.
The <aside> element (or role="complementary") represents content that supplements the main content, such as sidebars, related links, or additional context. When an <aside> is nested inside another landmark like <main> or <nav>, screen readers may not expose it as a top-level landmark. This means users who rely on landmark navigation may not be able to discover or jump to that complementary content at all, effectively hiding it from their navigation flow.
This issue primarily affects screen reader users, who depend on landmarks as a primary way to orient themselves and move through a page. When landmarks are improperly nested, the page structure becomes confusing or incomplete, reducing the efficiency and usability of assistive technology.
This rule relates to WCAG 2.1 Success Criterion 1.3.1 (Info and Relationships), which requires that information, structure, and relationships conveyed visually are also available programmatically. It also supports WCAG 2.1 Success Criterion 4.1.2 (Name, Role, Value) and the general best practice of using landmarks correctly so that assistive technologies can present content structure accurately.
How to Fix It
-
Move
<aside>elements to the top level of the document body, outside of<main>,<nav>,<header>,<footer>, or any other landmark. -
Check for
role="complementary"on any elements and ensure they are also placed at the top level, not nested inside another landmark. -
If the content truly belongs inside another landmark and is not meant to be independently navigable, consider whether it actually needs to be an
<aside>at all. A simple<div>or<section>without a landmark role may be more appropriate.
Examples
Incorrect: <aside> nested inside <main>
<main>
<h1>Article Title</h1>
<p>Main article content goes here.</p>
<aside>
<h2>Related Links</h2>
<ul>
<li><a href="/topic-a">Topic A</a></li>
<li><a href="/topic-b">Topic B</a></li>
</ul>
</aside>
</main>
In this example, the <aside> is inside <main>, so screen readers may not list it as a top-level landmark. Users navigating by landmarks could miss the related links entirely.
Correct: <aside> at the top level alongside <main>
<main>
<h1>Article Title</h1>
<p>Main article content goes here.</p>
</main>
<aside>
<h2>Related Links</h2>
<ul>
<li><a href="/topic-a">Topic A</a></li>
<li><a href="/topic-b">Topic B</a></li>
</ul>
</aside>
Now the <aside> is a sibling of <main>, making it a top-level landmark that screen reader users can easily discover and navigate to.
Incorrect: role="complementary" nested inside <nav>
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
<div role="complementary">
<p>Navigation tip: Use keyboard shortcuts to browse faster.</p>
</div>
</nav>
Correct: role="complementary" moved to the top level
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<div role="complementary" aria-label="Navigation tips">
<p>Navigation tip: Use keyboard shortcuts to browse faster.</p>
</div>
By keeping complementary landmarks at the top level of the page, you ensure all users — including those using assistive technology — can discover and navigate to every section of your content.
Landmarks are one of the primary ways screen reader users orient themselves on a page and navigate between major sections. The contentinfo landmark is specifically intended to hold site-wide footer information — copyright notices, privacy policies, contact links, and similar content. Screen readers like JAWS, NVDA, and VoiceOver provide shortcut keys that let users jump directly to landmarks by role.
When a contentinfo landmark is nested inside another landmark (such as main or navigation), it no longer appears as a top-level landmark in the screen reader’s landmark list. This means blind and deafblind users may not be able to find the footer information efficiently, or they may encounter it unexpectedly while navigating a different section of the page. The organizational benefit of landmarks is undermined when they are improperly nested.
This rule is a Deque best practice aligned with the broader principles of proper landmark usage recommended by the W3C’s ARIA Landmarks specification. While not mapped to a specific WCAG success criterion, correct landmark structure supports WCAG 1.3.1 (Info and Relationships), WCAG 2.4.1 (Bypass Blocks), and the overall goal of providing a clear, navigable document structure.
How to Fix It
-
Locate your
contentinfolandmark. This is either a<footer>element that is a direct child of<body>(which implicitly hasrole="contentinfo") or any element with an explicitrole="contentinfo". -
Check its position in the DOM. If the
contentinfolandmark is nested inside a<main>,<nav>,<aside>,<section>,<header>, or any element with a landmark role, it needs to be moved. -
Move it to the top level. Restructure your HTML so the
contentinfolandmark is a direct child of<body>, outside all other landmark regions.
Note that a <footer> element only has the implicit contentinfo role when it is scoped to the <body>. A <footer> nested inside an <article>, <section>, <aside>, <nav>, or <main> does not have the contentinfo role — it becomes a generic element. This means the issue typically arises when you explicitly add role="contentinfo" to a nested element, or when your page structure accidentally places the site-wide <footer> inside another landmark.
Examples
Incorrect: contentinfo Landmark Nested Inside main
<body>
<main>
<h1>Welcome</h1>
<p>Page content goes here.</p>
<footer>
<p>© 2024 Example Company</p>
</footer>
</main>
</body>
In this example, the <footer> is inside <main>, so it does not receive the implicit contentinfo role. If a developer tries to fix that by adding role="contentinfo" explicitly, the landmark becomes nested inside main, which triggers this rule:
<body>
<main>
<h1>Welcome</h1>
<p>Page content goes here.</p>
<div role="contentinfo">
<p>© 2024 Example Company</p>
</div>
</main>
</body>
Correct: contentinfo Landmark at the Top Level
<body>
<main>
<h1>Welcome</h1>
<p>Page content goes here.</p>
</main>
<footer>
<p>© 2024 Example Company</p>
</footer>
</body>
Here, the <footer> is a direct child of <body> and sits outside the <main> landmark. It automatically receives the implicit contentinfo role, and screen reader users can jump directly to it using landmark navigation.
Incorrect: Explicit role="contentinfo" Inside a region
<body>
<main>
<h1>Dashboard</h1>
</main>
<section aria-label="Additional info">
<footer role="contentinfo">
<p>Privacy Policy | Terms of Service</p>
</footer>
</section>
</body>
Correct: contentinfo Moved Outside the region
<body>
<main>
<h1>Dashboard</h1>
</main>
<footer>
<p>Privacy Policy | Terms of Service</p>
</footer>
</body>
The contentinfo landmark is now at the top level of the document, making it immediately discoverable through screen reader landmark navigation.
The <main> element (or role="main") represents the dominant content of a page — the content that is directly related to the central topic or functionality. Screen reader users rely on landmark navigation to jump quickly between major sections of a page, such as the banner, navigation, main content, and footer. When the <main> landmark is nested inside another landmark, this hierarchy becomes confusing. A screen reader might present it as a subsection of, say, the navigation or banner, making it harder for users to understand the page structure and locate the primary content efficiently.
This rule primarily affects users who are blind, deafblind, or have mobility impairments and depend on assistive technologies to navigate by landmarks. When landmarks are properly structured as flat, top-level regions, users can cycle through them predictably and efficiently.
Why landmark hierarchy matters
The HTML Living Standard specifies that a hierarchically correct <main> element is one whose ancestor elements are limited to <html>, <body>, <div>, <form> without an accessible name, and autonomous custom elements. This means <main> should never appear inside <header>, <nav>, <aside>, <footer>, or any element with a landmark role.
Think of landmarks as the top-level sections of your page. They should be siblings, not nested within each other. A well-structured page has a clear, flat hierarchy of landmarks:
-
Banner (
<header>orrole="banner") — site-wide header content -
Navigation (
<nav>orrole="navigation") — navigation links -
Main (
<main>orrole="main") — primary page content -
Contentinfo (
<footer>orrole="contentinfo") — footer content
This rule is classified as a Deque best practice and supports the broader principle of providing clear, navigable page structure for assistive technology users.
How to fix it
-
Move
<main>out of any enclosing landmark. If your<main>element is nested inside a<header>,<nav>,<aside>,<footer>, or any element with an ARIA landmark role, restructure your markup so<main>is a direct child of<body>(or only wrapped in non-landmark elements like<div>). - Ensure landmarks are siblings, not nested. The primary landmarks — banner, navigation, main, and contentinfo — should sit at the same level in the DOM.
-
Use both HTML5 elements and ARIA roles for maximum compatibility. While modern browsers and screen readers handle HTML5 landmark elements well, adding the corresponding ARIA role (e.g.,
<main role="main">) provides a fallback for older assistive technologies.
Examples
Incorrect: <main> nested inside another landmark
In this example, the <main> element is nested inside the <nav> landmark, which breaks the expected landmark hierarchy.
<header role="banner">
<p>Company Logo</p>
</header>
<nav role="navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
<main role="main">
<p>This is the primary content, incorrectly nested inside nav.</p>
</main>
</nav>
<footer role="contentinfo">
<p>Copyright 2024</p>
</footer>
Incorrect: <main> nested inside <aside>
<aside role="complementary">
<main role="main">
<p>Main content should not be inside a complementary landmark.</p>
</main>
</aside>
Correct: <main> as a top-level landmark
All landmarks are siblings at the top level of the document. The <main> element is not contained within any other landmark.
<header role="banner">
<p>Company Logo</p>
</header>
<nav role="navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<main role="main">
<p>This is the primary content of the page.</p>
</main>
<footer role="contentinfo">
<p>Copyright 2024</p>
</footer>
Correct: <main> wrapped in a non-landmark <div>
Wrapping <main> in a <div> is acceptable because <div> is not a landmark element.
<header role="banner">
<p>Company Logo</p>
</header>
<div class="content-wrapper">
<main role="main">
<p>This is the primary content of the page.</p>
</main>
</div>
<footer role="contentinfo">
<p>Copyright 2024</p>
</footer>
Landmarks are structural markers that allow assistive technology users to quickly navigate to key sections of a page. Screen readers like JAWS, NVDA, and VoiceOver provide shortcut keys that let users jump directly to landmarks such as the banner, navigation, main content, and footer. When a page has more than one banner landmark, users encounter ambiguity — they can’t tell which banner is the primary site-wide header, defeating the purpose of landmark navigation.
This issue primarily affects blind users and deafblind users who rely on screen readers, as well as sighted keyboard users who may use browser extensions for landmark navigation. When landmarks are duplicated, these users must spend extra time sorting through repeated or redundant regions to find the content they need.
This rule is a Deque best practice for accessible landmark structure. While it doesn’t map to a specific WCAG success criterion, it directly supports the goals of WCAG 1.3.1 Info and Relationships and WCAG 2.4.1 Bypass Blocks by ensuring that the page structure is logical and navigable.
Understanding the Banner Landmark
A banner landmark represents the site-wide header — the region that typically contains the site logo, site name, global navigation, and search. There are two ways a banner landmark is created:
-
A
<header>element that is a direct child of<body>(not nested inside<main>,<article>,<section>,<aside>, or<nav>) automatically has an implicitrole="banner". -
Any element with
role="banner"explicitly assigned.
Although the HTML5 spec allows multiple <header> elements on a page, only a top-level <header> maps to the banner landmark role. A <header> nested inside an <article> or <section> does not become a banner landmark — it’s simply a header for that section. The confusion arises when developers place multiple <header> elements directly under <body>, or mix explicit role="banner" with a top-level <header>.
How to Fix It
-
Identify all banner landmarks on your page. Look for top-level
<header>elements and any element withrole="banner". - Keep only one as the primary site-wide banner. This should be the header that contains your site logo, site name, or global navigation.
-
Remove or restructure any additional banner landmarks:
-
If you have extra
<header>elements at the top level, nest them inside a sectioning element like<section>or<article>so they lose their implicit banner role. -
If you have extra
role="banner"attributes, remove them.
-
If you have extra
-
Don’t use
role="banner"on a<header>that is already a direct child of<body>— it’s redundant. Conversely, don’t addrole="banner"to multiple elements.
Examples
Incorrect: Multiple Banner Landmarks
<body>
<header>
<h1>My Website</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<header>
<p>Welcome to the promotional section</p>
</header>
<main>
<p>Page content here.</p>
</main>
</body>
Both <header> elements are direct children of <body>, so both become banner landmarks. Screen readers will report two banners.
Incorrect: Mixing role="banner" with a Top-Level <header>
<body>
<header>
<h1>My Website</h1>
</header>
<div role="banner">
<p>Site-wide announcement</p>
</div>
<main>
<p>Page content here.</p>
</main>
</body>
The <header> implicitly has role="banner", and the <div> explicitly has role="banner", resulting in two banner landmarks.
Correct: Single Banner Landmark
<body>
<header>
<h1>My Website</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<main>
<article>
<header>
<h2>Article Title</h2>
<p>Published on January 1, 2025</p>
</header>
<p>Article content here.</p>
</article>
</main>
</body>
Only the first <header> is a direct child of <body> and maps to the banner landmark. The second <header> is nested inside <article>, so it does not create a banner landmark.
Correct: Using role="banner" on a Single Element
<body>
<div role="banner">
<h1>My Website</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</div>
<main>
<p>Page content here.</p>
</main>
</body>
Only one element carries the banner role, so screen readers correctly identify a single banner landmark.
Landmarks are one of the primary ways screen reader users orient themselves on a page. Tools like JAWS, NVDA, and VoiceOver allow users to pull up a list of landmarks and jump directly to any one of them. The contentinfo landmark typically contains information like copyright notices, privacy policies, and contact links that apply to the entire page. When multiple contentinfo landmarks exist, screen reader users encounter duplicate entries in their landmarks list and cannot tell which one is the actual page footer. This creates confusion and slows down navigation.
The contentinfo landmark is generated in two ways: by adding role="contentinfo" to an element, or by using a <footer> element that is a direct child of <body> (or not nested inside <article>, <aside>, <main>, <nav>, or <section>). A <footer> nested inside one of those sectioning elements does not map to the contentinfo role, so it won’t trigger this issue. However, role="contentinfo" explicitly applied to any element will always create a contentinfo landmark regardless of nesting.
Who is affected
-
Screen reader users (blind and deafblind users) rely on landmark navigation to move efficiently through a page. Duplicate
contentinfolandmarks clutter the landmarks list and make it harder to find the real page footer. - Sighted keyboard users who use browser extensions or assistive tools for landmark-based navigation are also affected.
Related standards
This rule is a Deque best practice. While not mapped to a specific WCAG success criterion, it supports the principles behind WCAG 1.3.1 Info and Relationships and WCAG 2.4.1 Bypass Blocks, which emphasize correct semantic structure and efficient navigation. The ARIA specification itself states that role="banner", role="main", and role="contentinfo" should each be used only once per page.
How to fix it
-
Audit your page for all elements that create a
contentinfolandmark. Search forrole="contentinfo"and for top-level<footer>elements. -
Keep only one
contentinfolandmark that represents the site-wide footer. -
If you need footer-like content inside articles or sections, use
<footer>nested within<article>,<section>, or<main>— these do not create acontentinfolandmark. -
Remove any extra
role="contentinfo"attributes from elements that are not the page-level footer.
Examples
Bad example: multiple contentinfo landmarks
In this example, role="contentinfo" is used on two separate elements, creating duplicate contentinfo landmarks. The <footer> at the bottom also creates a third one since it is a direct child of <body>.
<header>Visit Your Local Zoo!</header>
<main>
<h1>The Nature of the Zoo</h1>
<article>
<h2>In the Zoo: From Wild to Tamed</h2>
<p>What you see in the zoo are examples of inborn traits left undeveloped.</p>
<div role="contentinfo">
<p>Article metadata here</p>
</div>
</article>
<article>
<h2>Feeding Frenzy: The Impact of Cohabitation</h2>
<p>Some animals naturally group together with their own kind.</p>
<div role="contentinfo">
<p>Article metadata here</p>
</div>
</article>
</main>
<footer>
<p>Brought to you by North American Zoo Partnership</p>
</footer>
Good example: single contentinfo landmark
Here, role="contentinfo" is used exactly once for the page footer. Article-level footers use <footer> nested inside <article>, which does not create a contentinfo landmark.
<div role="banner">
<p>Visit Your Local Zoo!</p>
</div>
<div role="main">
<h1>The Nature of the Zoo</h1>
<article>
<h2>In the Zoo: From Wild to Tamed</h2>
<p>What you see in the zoo are examples of inborn traits left undeveloped.</p>
<footer>
<p>Article metadata here</p>
</footer>
</article>
<article>
<h2>Feeding Frenzy: The Impact of Cohabitation</h2>
<p>Some animals naturally group together with their own kind.</p>
<footer>
<p>Article metadata here</p>
</footer>
</article>
</div>
<div role="contentinfo">
<p>Brought to you by North American Zoo Partnership</p>
</div>
Good example: using semantic HTML5 elements
This version uses HTML5 semantic elements. The single top-level <footer> maps to the contentinfo role. The <footer> elements inside each <article> do not.
<header>
<p>Visit Your Local Zoo!</p>
</header>
<main>
<h1>The Nature of the Zoo</h1>
<article>
<h2>In the Zoo: From Wild to Tamed</h2>
<p>What you see in the zoo are examples of inborn traits left undeveloped.</p>
<footer>
<p>Article metadata here</p>
</footer>
</article>
<article>
<h2>Feeding Frenzy: The Impact of Cohabitation</h2>
<p>Some animals naturally group together with their own kind.</p>
<footer>
<p>Article metadata here</p>
</footer>
</article>
</main>
<footer>
<p>Brought to you by North American Zoo Partnership</p>
</footer>
What this rule checks
The axe-core rule landmark-no-duplicate-contentinfo finds all elements that map to the contentinfo landmark role, filters out any that don’t actually resolve to that role (such as <footer> elements nested inside sectioning elements), and verifies that only one contentinfo landmark remains on the page. If more than one is found, the rule reports a violation.
Landmarks are semantic regions that help assistive technology users understand the structure of a page and jump between sections efficiently. The main landmark specifically identifies the primary content area — the unique content that distinguishes this page from others on the site. When multiple main landmarks exist, screen readers present all of them in the landmarks list, making it unclear which one contains the actual primary content.
This issue primarily affects blind and deafblind users who rely on screen readers, as well as keyboard-only users with mobility disabilities who use landmark-based navigation. Screen readers like JAWS, NVDA, and VoiceOver allow users to press a shortcut key to jump directly to the main landmark. If there are two or more main landmarks, the user must guess which is correct, defeating the purpose of this navigational aid.
While this rule is categorized as a Deque best practice rather than a specific WCAG success criterion violation, it strongly supports WCAG 1.3.1 (Info and Relationships) and WCAG 2.4.1 (Bypass Blocks). Properly structured landmarks help users understand page organization and skip repetitive content.
How to Fix It
-
Audit your page for duplicate
mainlandmarks. Search your HTML for multiple<main>elements or multiple uses ofrole="main". Remember that a<main>element has an implicitrole="main", so a<main>and a<div role="main">on the same page creates a duplicate. -
Consolidate into a single
mainlandmark. Wrap all primary content in one<main>element and remove any others. -
Check iframes. If your page contains
<iframe>elements, ensure each iframe’s document also has at most onemainlandmark. -
Use complementary landmarks for other sections. Content that is not the primary focus — such as sidebars — should use
<aside>(orrole="complementary") instead of<main>.
It’s also a good practice to structure your entire page with semantic HTML5 landmark elements — <header>, <nav>, <main>, and <footer> — so all content is contained within a recognizable region. You can pair these with their ARIA equivalents (role="banner", role="navigation", role="main", role="contentinfo") for maximum compatibility across screen readers, though modern browsers and assistive technologies handle the HTML5 elements well on their own.
Examples
Incorrect: Multiple main Landmarks
This page has two main landmarks, which makes it ambiguous for screen reader users.
<header>
<h1>My Website</h1>
</header>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<main>
<h2>Articles</h2>
<p>Article content here.</p>
</main>
<main>
<h2>Sidebar</h2>
<p>Related links and info.</p>
</main>
<footer>
<p>© 2024 My Website</p>
</footer>
Incorrect: Mixing <main> with role="main"
Even though these are different elements, both create a main landmark, resulting in duplicates.
<main>
<p>Primary content here.</p>
</main>
<div role="main">
<p>More content here.</p>
</div>
Correct: Single main Landmark with Proper Page Structure
All primary content is in one <main> element, and the sidebar uses <aside> instead.
<header>
<h1>My Website</h1>
</header>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<main>
<h2>Articles</h2>
<p>Article content here.</p>
</main>
<aside>
<h2>Sidebar</h2>
<p>Related links and info.</p>
</aside>
<footer>
<p>© 2024 My Website</p>
</footer>
Correct: Page with an Iframe
The parent page and the iframe document each have at most one main landmark.
<!-- Parent page -->
<main>
<h1>Dashboard</h1>
<iframe src="widget.html" title="Statistics widget"></iframe>
</main>
<!-- widget.html -->
<main>
<p>Widget content here.</p>
</main>
Landmarks are structural regions of a page — like header, navigation, main content, and footer — that assistive technologies use to build an outline of the page. When a screen reader user opens a page, they can pull up a list of landmarks and jump directly to the section they need. Without a main landmark, there is no way for these users to skip past repeated headers and navigation to reach the content they came for. This makes the page significantly harder to use.
This rule is a Deque best practice aligned with the WAI-ARIA technique ARIA11: Using ARIA landmarks to identify regions of a page. Users who are blind, deafblind, or who have mobility impairments and rely on screen readers or alternative navigation methods are the most directly affected. Without landmarks, these users must tab or arrow through every element on the page to find the content they need.
How landmarks work
HTML5 introduced semantic elements that automatically create landmark regions:
| HTML5 Element | Implicit ARIA Role |
|---|---|
<header> |
role="banner" |
<nav> |
role="navigation" |
<main> |
role="main" |
<footer> |
role="contentinfo" |
<aside> |
role="complementary" |
Modern browsers and screen readers understand these HTML5 elements natively. For maximum compatibility, you can also add the explicit ARIA role alongside the HTML5 element (e.g., <main role="main">). This redundancy is harmless and can help with older assistive technologies.
How to fix the problem
-
Wrap your primary content in a
<main>element. Every page should have exactly one<main>landmark. -
Place all other visible content inside appropriate landmarks. Use
<header>,<nav>,<footer>, and<aside>as needed so that no content is orphaned outside a landmark region. -
Check
iframeelements. If aniframecontains landmarked content, it should have no more than one<main>landmark. -
Don’t nest
<main>elements. There should be only one<main>per page (or periframe).
Note that landmarks primarily benefit screen reader users. Sighted users and screen magnifier users don’t perceive landmarks, so they still need visible skip-navigation links to bypass repeated content.
Examples
Incorrect: no main landmark
This page has no <main> element, so screen reader users have no way to jump directly to the primary content.
<header>
<p>Company Logo</p>
</header>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<div class="content">
<p>This is the primary content of the page.</p>
</div>
<footer>
<p>© 2024 Company Name</p>
</footer>
Correct: page with one main landmark
Replacing the generic <div> with a <main> element gives screen reader users a direct navigation point to the primary content.
<header>
<p>Company Logo</p>
</header>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<main>
<p>This is the primary content of the page.</p>
</main>
<footer>
<p>© 2024 Company Name</p>
</footer>
Correct: using both HTML5 elements and ARIA roles for maximum compatibility
<header role="banner">
<p>Company Logo</p>
</header>
<nav role="navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<main role="main">
<p>This is the primary content of the page.</p>
</main>
<footer role="contentinfo">
<p>© 2024 Company Name</p>
</footer>
Incorrect: multiple main landmarks
Having more than one <main> element confuses assistive technologies about which section is the true primary content.
<main>
<p>Article content here.</p>
</main>
<main>
<p>Sidebar content here.</p>
</main>
Correct: single main with an aside for secondary content
<main>
<p>Article content here.</p>
</main>
<aside>
<p>Sidebar content here.</p>
</aside>
HTML landmark elements like <header>, <nav>, <main>, <aside>, <form>, <section>, and <footer> — as well as elements with explicit ARIA landmark roles — create navigational waypoints that assistive technologies expose to users. Screen readers often provide a list of all landmarks on the page or allow users to jump between them using keyboard shortcuts. When two or more landmarks share the same role and have no accessible name (or share the same accessible name), they appear identical in that list. A user hearing “navigation” and “navigation” has no way of knowing whether the first is the site-wide menu and the second is a breadcrumb trail.
This issue primarily affects blind users, deafblind users, and sighted keyboard users who rely on assistive technology landmark navigation features. It is flagged as a Deque best practice rule. While it doesn’t map directly to a specific WCAG success criterion, it strongly supports the intent of WCAG 1.3.1 (Info and Relationships) and WCAG 2.4.1 (Bypass Blocks), which require that structural information is programmatically available and that users have mechanisms to navigate past repeated blocks of content.
How to Fix the Problem
The fix depends on whether you truly need multiple landmarks of the same type:
- If only one landmark of a given role exists on the page, no additional labeling is needed — it’s already unique by its role alone.
-
If multiple landmarks share the same role, give each a unique accessible name using
aria-labeloraria-labelledby. - If duplicate landmarks aren’t necessary, consider removing or consolidating them.
When choosing accessible names, pick labels that clearly describe the purpose of each landmark, such as “Primary navigation,” “Footer navigation,” or “Search form.”
Examples
Incorrect: Duplicate <nav> landmarks with no accessible names
Screen reader users see two identical “navigation” landmarks with no way to tell them apart.
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
<nav>
<a href="/terms">Terms</a>
<a href="/privacy">Privacy</a>
</nav>
Correct: Duplicate <nav> landmarks with unique accessible names
Each landmark now has a distinct label that screen readers announce.
<nav aria-label="Main">
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
<nav aria-label="Footer">
<a href="/terms">Terms</a>
<a href="/privacy">Privacy</a>
</nav>
Incorrect: Two <aside> elements with the same aria-label
Even though labels are present, they are identical, so the landmarks are still indistinguishable.
<aside aria-label="Related content">
<p>Popular articles</p>
</aside>
<aside aria-label="Related content">
<p>Recommended products</p>
</aside>
Correct: Two <aside> elements with unique aria-label values
<aside aria-label="Popular articles">
<p>Popular articles</p>
</aside>
<aside aria-label="Recommended products">
<p>Recommended products</p>
</aside>
Correct: Using aria-labelledby to reference visible headings
If your landmarks already contain headings, you can point to those headings instead of duplicating text in aria-label.
<nav aria-labelledby="nav-main-heading">
<h2 id="nav-main-heading">Main Menu</h2>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<nav aria-labelledby="nav-breadcrumb-heading">
<h2 id="nav-breadcrumb-heading">Breadcrumb</h2>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
Correct: Only one landmark of a given role — no label needed
When a landmark role appears only once on the page, it is inherently unique.
<header>
<h1>My Website</h1>
</header>
<main>
<p>Page content goes here.</p>
</main>
<footer>
<p>© 2024 My Website</p>
</footer>
Incorrect: Duplicate ARIA landmark roles without unique names
Using explicit ARIA roles doesn’t change the requirement — duplicates still need unique names.
<div role="complementary">
<p>Sidebar content A</p>
</div>
<div role="complementary">
<p>Sidebar content B</p>
</div>
Correct: Explicit ARIA landmark roles with unique accessible names
<div role="complementary" aria-label="Author bio">
<p>Sidebar content A</p>
</div>
<div role="complementary" aria-label="Related links">
<p>Sidebar content B</p>
</div>
Links are one of the most fundamental interactive elements on the web. When a link lacks an accessible name, screen reader users hear something like “link” with no further context, making it impossible to understand the link’s purpose or destination. This affects people who are blind, deafblind, or have low vision and rely on screen readers, as well as keyboard-only users who navigate through links sequentially.
A link’s accessible name can come from several sources: its visible text content, an aria-label attribute, an aria-labelledby reference, a title attribute, or the alt text of an image contained within it. If none of these provide a non-empty string, the link has no discernible text, and this rule will flag it.
Beyond just having text, links must also be programmatically focusable. Avoid relying on device-specific JavaScript events like onmouseover or mouseout(), which are inaccessible to keyboard users. Use device-independent alternatives like onfocus, onblur, focus(), and blur(). Additionally, don’t hide link text from assistive technologies using display: none, visibility: hidden, or aria-hidden="true" on the link or its text content.
It’s also important to use semantic <a> elements with a valid href attribute rather than simulating links with <span> or <div> elements and click handlers. Real links are focusable by default and convey the correct role to assistive technologies.
Related WCAG Success Criteria
This rule relates to two Level A success criteria that apply across WCAG 2.0, 2.1, and 2.2:
- WCAG 2.4.4 (Link Purpose in Context): Users must be able to determine the purpose of each link from the link text alone, or from the link text combined with its programmatically determined context.
- WCAG 4.1.2 (Name, Role, Value): All user interface components, including links, must have an accessible name and role that can be programmatically determined.
This rule is also required under Section 508, EN 301 549, and Trusted Tester guidelines.
How to Fix It
-
Add visible text content inside the
<a>element. -
For image links, provide meaningful
alttext on the<img>element. -
Use
aria-labelwhen you need to provide an accessible name that differs from or supplements the visible text. -
Use
aria-labelledbyto reference another element’s text as the link’s accessible name. -
Don’t hide link text from screen readers with
aria-hidden="true"or CSS that removes elements from the accessibility tree. -
Ensure links are focusable by using proper
<a>elements withhrefattributes and avoiding mouse-only event handlers.
Examples
Empty link (incorrect)
A link with no text or accessible name:
<a href="/settings"></a>
A link that only contains an image with no alt text:
<a href="/home">
<img src="logo.png" alt="">
</a>
A link with its text hidden from assistive technologies:
<a href="/profile">
<span aria-hidden="true">Profile</span>
</a>
Link with visible text (correct)
<a href="/settings">Settings</a>
Image link with descriptive alt text (correct)
<a href="/home">
<img src="logo.png" alt="Homepage">
</a>
Link with aria-label (correct)
This is useful when multiple links share the same visible text, such as repeated “Read more” links:
<h3>Accessibility Updates</h3>
<p>New WCAG 2.2 guidelines have been published.
<a href="/wcag22" aria-label="Read more about WCAG 2.2 updates">Read more</a>
</p>
<h3>Screen Reader Tips</h3>
<p>Learn how to navigate tables with a screen reader.
<a href="/sr-tips" aria-label="Read more about screen reader tips">Read more</a>
</p>
Link with aria-labelledby (correct)
<h3 id="report-title">Annual Report 2024</h3>
<a href="/report-2024.pdf" aria-labelledby="report-title">Download PDF</a>
Icon link with visually hidden text (correct)
For links that use icons without visible text, use a visually hidden <span> to provide an accessible name:
<a href="/search">
<svg aria-hidden="true" focusable="false">
<use href="#icon-search"></use>
</svg>
<span class="visually-hidden">Search</span>
</a>
The visually-hidden class hides the text visually but keeps it available to screen readers:
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}