ADA Compliance Professionals

    Presentational elements must not be focusable or have ARIA

    Last updated:

    Who it helps:
    Blind
    Mobility
    Standard:
    WCAG 2.2 Level A

    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 tabindex attributes after refactoring markup.

    How to Fix

    1. Inventory presentational roles:
      • Find all [role="none"] and [role="presentation"]. Decide if each element is truly decorative.
    2. Remove focusability:
      • Delete tabindex entirely (do not use tabindex="-1" on decorative nodes).
      • Strip interactive attributes/semantics (remove href on anchors used for layout; do not use <button>/<input> for decoration).
    3. 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.
    4. 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="" or role="presentation" (not both), and ensure no tabindex and not wrapped in a link.
    5. Avoid invalid usage:
      • Do not apply role="none" to controls or elements required for interaction (links, buttons, form controls, details/summary). Use proper semantics.
    6. Prefer CSS for decoration:
      • Move purely visual elements to CSS backgrounds or ::before/::after pseudo-elements to avoid extra DOM nodes.
    7. 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.

    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:
    JS
      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.

    HTML
    <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.

    HTML
    <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 tabindex and are never focusable.
    • No global ARIA attributes exist on presentational elements.
    • Presentational roles are not applied to interactive controls.
    • Decorative images use alt="" or role="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.
    Note: s:
    • Relevant WCAG 2.2: 1.3.1 Info and Relationships, 4.1.2 Name, Role, Value.