ADA Compliance Professionals

    Headings must include discernible text

    Last updated:

    Who it helps:
    Blind
    Standard:
    WCAG 2.2 Level AA

    Headings must not be empty and must have discernible text

    Every heading element must expose readable text to assistive technologies. Empty or hidden headings create “blank” announcements and break the page outline. This affects screen reader users and anyone who navigates by headings on desktop and mobile.

    Why It Matters

    People who use screen readers jump through content by heading level. An empty or hidden heading is announced as blank, which is confusing and wastes time.

    Clear, descriptive headings reduce cognitive load and help users understand section purpose. Consistent structure benefits speech recognition users who issue voice commands like “go to next heading.”

    Search engines also interpret heading structure, so meaningful text improves document semantics.

    Common Causes

    • Using empty h1–h6 tags as spacers or layout hooks.
    • Hiding heading text with aria-hidden="true" or CSS like display:none or visibility:hidden.
    • Rendering heading text only via background images or CSS ::before/::after content.
    • Icon-only headings with no accessible text alternative.
    • JavaScript inserting heading elements without textContent or accessible name.
    • role="heading" used without a valid aria-level or without a name.

    How to Fix

    1. Use semantic h1–h6 for section titles. Provide real text nodes inside the heading.
    2. Do not apply aria-hidden="true" to any heading or its text. Remove it if present.
    3. Do not hide the only heading text with display:none or visibility:hidden. If text must be visually hidden while remaining accessible, use a “visually hidden” utility that keeps it available to assistive tech.
    4. Do not rely on CSS-generated content or background images for critical heading text. Put the words in the DOM.
    5. Replace empty spacer headings with proper CSS spacing (margins, padding) and remove the empty tags.
    6. If you must use role="heading" (e.g., in a widget), include aria-level="1–6" and an accessible name via text, aria-label, or aria-labelledby.
    7. Make headings descriptive of their section purpose (WCAG 2.2: 1.3.1 Info and Relationships, 2.4.6 Headings and Labels, 4.1.2 Name, Role, Value).

    Recommendation: Favor visible text in headings whenever possible; reserve visually hidden text for rare icon-only designs.

    How to Test

    • Visual/DOM check:
    • Inspect each h1–h6. Confirm there is textContent or an accessible name.
    • Ensure no aria-hidden on the heading or on its only text node.
    • Verify text is not removed with display:none or visibility:hidden.
    • Confirm text is not solely from ::before/::after or background images.
    • Keyboard check (informational):
    • Tabbing should not land on headings (they are not interactive). If a heading receives focus, review why and remove tabindex unless necessary for a composite widget.
    • Screen reader check (desktop):
    • NVDA/JAWS: Press H to move by headings and use the headings list (NVDA: Insert+F7 > Headings; JAWS: Insert+F6). No item should be blank; each entry should read meaningful text and level.
    • VoiceOver (macOS): VO+U to open the Rotor, choose Headings. Ensure each heading has text and correct order.
    • Mobile/touch check:
    • iOS VoiceOver: Use the Rotor set to Headings and swipe up/down to navigate. Confirm there are no empty announcements.
    • Android TalkBack: Use the reading controls for Headings and navigate. Ensure all headings are announced with text.
    • Automated check:
    • Run an a11y scanner that flags “headings must have discernible text.” Manually confirm any flagged items.

    Good Example

    HTML
    <h2 class="section-title">
      <span class="icon-bell" aria-hidden="true"></span>
      Notifications
    </h2>
    
    <!-- Icon-only visual design with accessible, visually hidden text -->
    <h3 class="section-title">
      <span class="icon-stats" aria-hidden="true"></span>
      <span class="sr-only">Sales Dashboard</span>
    </h3>
    
    <style>
    .sr-only {
      position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
      overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
    }
    </style>

    Bad Example

    HTML
    <h2></h2> <!-- empty -->
    <h3 aria-hidden="true">Support</h3> <!-- hidden from AT -->
    <h4><span class="icon-help" aria-hidden="true"></span></h4> <!-- icon-only, no text -->

    Quick Checklist

    • Every h1–h6 contains real, readable text in the DOM.
    • No heading or its only text node is aria-hidden.
    • Heading text is not removed with display:none or visibility:hidden.
    • Do not rely on CSS-generated content or images for heading words.
    • Icon-only headings include an accessible text alternative.
    • role="heading" (if used) includes aria-level and an accessible name.
    • Headings describe the topic or purpose of their section.
    • Remove empty headings; use CSS for spacing instead.