Presentational elements must not be focusable or have ARIA
Last updated:
Related Guides
Presentational elements must not be focusable or use global ARIA
If you set role="none" or role="presentation", the element must be removed from the accessibility tree and must not be focusable or carry global ARIA attributes.
This issue appears on decorative wrappers, icons, layout spans, and structural list/table containers.
When presentational roles conflict with focusability or ARIA, assistive technologies treat the element as interactive or meaningful, confusing users.
Why It Matters
Screen reader users rely on the accessibility tree. If a node marked presentational still exposes a role, name, or focus, it gets announced or becomes a tab stop. That adds noise and breaks expected reading order.
Keyboard users can land on elements that were intended to be ignored, creating extra stops and potential traps. Cognitive load increases when controls appear without purpose or label.
For low-vision and screen magnification users, unexpected focus indicators on decorative pieces are disorienting.
Common Causes
- Adding
tabindex(of any value) to elements with role="none"/"presentation". - Applying
role="none"to inherently interactive elements (buttons, links with href, inputs, details/summary). - Including global ARIA on presentational elements (e.g.,
aria-label,aria-labelledby,aria-describedby,aria-live,aria-pressed). - JavaScript setting focus to a decorative node (element.focus()).
- Leaving leftover ARIA or
tabindexattributes after refactoring markup.
How to Fix
- Inventory presentational roles:
- Find all
[role="none"]and[role="presentation"]. Decide if each element is truly decorative.
- Find all
- Remove focusability:
- Delete
tabindexentirely (do not usetabindex="-1"on decorative nodes). - Strip interactive attributes/semantics (remove href on anchors used for layout; do not use <button>/<input> for decoration).
- Delete
- Remove global ARIA from presentational elements:
- Delete
aria-label,aria-labelledby,aria-describedby,aria-live, and other global aria-* on those nodes. - If you need ARIA to convey meaning, the element is not decorative—remove the presentational role and give it the correct semantic role and accessible name instead.
- Delete
- Choose the right hiding strategy:
- Decorative only: keep role="none"/"presentation" OR use aria-hidden="true"—not both. Ensure not focusable.
- Images purely decorative: use
alt=""orrole="presentation"(not both), and ensure notabindexand not wrapped in a link.
- Avoid invalid usage:
- Do not apply
role="none"to controls or elements required for interaction (links, buttons, form controls, details/summary). Use proper semantics.
- Do not apply
- Prefer CSS for decoration:
- Move purely visual elements to CSS backgrounds or ::before/::after pseudo-elements to avoid extra DOM nodes.
- Verify parent/child semantics:
- If using
role="presentation"on structural containers (e.g., lists/tables), ensure child content remains perceivable and not focusable unless intended.
- If using
How to Test
- Keyboard check:
- Tab through the page. Elements with role="none"/"presentation" must never receive focus or show a focus indicator.
- Ensure no script moves focus to decorative nodes.
- Screen reader check (NVDA/JAWS/VoiceOver/TalkBack):
- Read line-by-line where presentational elements exist. They should not be announced or listed as controls.
- Check rotor/element lists (links, buttons, landmarks). Decorative nodes must not appear.
- DOM/a11y tree check:
- In browser devtools, open the Accessibility panel. Confirm nodes with role="none"/"presentation" do not expose a role/name and are not focusable.
- Quick query to spot risks:
document.querySelectorAll('[role="none"], [role="presentation"]').forEach(el => {
const hasAria = Array.from(el.attributes).some(a => a.name.startsWith('aria-'));
const hasTabindex = el.hasAttribute('tabindex');
const nativelyFocusable = ['A','BUTTON','INPUT','SELECT','TEXTAREA','SUMMARY'].includes(el.tagName) || el.hasAttribute('href');
if (hasAria || hasTabindex || nativelyFocusable) {
console.warn('Fix presentational element:', el);
}
});Good Example
A decorative star icon before a link, not focusable and no ARIA on the presentational node.
<ul class="menu">
<li>
<a href="/pricing">
<span class="icon-star" role="presentation"></span>
Pricing
</a>
</li>
</ul>
.icon-star { display:inline-block; width:1em; height:1em; background: url('/icons/star.svg') no-repeat center contain; }Bad Example
Decorative node mis-marked as presentational but still has global ARIA and can be focused programmatically.
<a href="/pricing">
<span class="icon-star" role="presentation" aria-label="star" tabindex="-1"></span>
Pricing
</a>
<!-- Another mistake: using a button for decoration -->
<button role="none" class="divider" aria-hidden="true"></button>Quick Checklist
- Elements with role="none"/"presentation" have no
tabindexand are never focusable. - No global ARIA attributes exist on presentational elements.
- Presentational roles are not applied to interactive controls.
- Decorative images use
alt=""orrole="presentation", not both. - If ARIA is needed, remove the presentational role and provide correct semantics and name.
- JavaScript never moves focus to decorative nodes.
- Optional: prefer CSS backgrounds/pseudo-elements instead of extra decorative DOM.
- Relevant WCAG 2.2: 1.3.1 Info and Relationships, 4.1.2 Name, Role, Value.