Skip to main content
Accessibility Axe Core 4.11

role='text' should have no focusable descendants

About This Accessibility Rule

The role="text" attribute is a workaround for a specific screen reader behavior. When a text node is split by inline markup — for example, <h1>Good morning, <span>friend</span></h1> — VoiceOver on macOS and iOS may announce this as two separate phrases instead of reading it as one continuous string. Wrapping the content in an element with role="text" tells the screen reader to treat everything inside as a single text node, which produces a smoother reading experience.

However, role="text" comes with an important side effect: it overrides the semantic role of the container element and all of its descendants. Every child element is effectively treated as plain text. This means that if any descendant is focusable — such as an <a>, <button>, or <input> — the screen reader can no longer recognize it for what it is. The element remains in the tab order because the browser still considers it focusable, but VoiceOver will not announce its name, role, or value. The result is a “ghost” tab stop: the user presses Tab, focus moves to an element, but nothing is announced. This is a serious problem for blind users and keyboard-only users who rely on focus announcements to navigate and interact with a page.

Who is affected

  • Blind users using screen readers like VoiceOver cannot identify focusable elements trapped inside a role="text" container. They encounter empty tab stops with no announcement.
  • Keyboard-only users experience confusing focus behavior — tabbing lands on elements that provide no information about what they are or what they do.
  • Users with low vision who use screen readers in combination with magnification may also be impacted.

Related standards

This rule is classified as a Deque Best Practice. While it does not map directly to a specific WCAG success criterion, it relates closely to:

  • WCAG 4.1.2 (Name, Role, Value): All user interface components must have an accessible name and role that can be programmatically determined. A focusable element inside role="text" loses its role and may lose its accessible name.
  • WCAG 2.4.7 (Focus Visible): Users must be able to understand where focus is. An empty tab stop with no screen reader announcement undermines this.
  • WCAG 2.1.1 (Keyboard): All functionality must be operable through a keyboard. If a user cannot identify a focusable element, they effectively cannot use it.

How to fix it

  1. Move focusable elements outside the role="text" container so they retain their semantic roles and are properly announced.
  2. Only wrap non-interactive content with role="text". Use it exclusively for its intended purpose: merging split text nodes into a single phrase for screen readers.
  3. Remove role="text" entirely if the content includes interactive elements and you cannot restructure the markup. It is better to have VoiceOver announce text in separate phrases than to create inaccessible interactive elements.

Examples

Incorrect: focusable link inside role="text"

The link is inside the role="text" container, so VoiceOver treats it as plain text. The user can Tab to the link, but nothing is announced.

<p role="text">
  For more details, visit
  <a href="/about">our about page</a>.
</p>

Incorrect: focusable button inside role="text"

<div role="text">
  Your session is about to expire.
  <button>Extend session</button>
</div>

Correct: role="text" wraps only non-interactive content

The role="text" is applied to a <span> that contains no focusable elements, while the link sits outside it.

<p>
  <span role="text">Good morning, <span>friend</span></span>.
  Visit <a href="/dashboard">your dashboard</a> to get started.
</p>

Correct: role="text" on a heading with split text nodes

This is the primary use case for role="text" — ensuring VoiceOver reads a heading as a single phrase rather than separate fragments.

<h1>
  <span role="text">Hello <br/>World</span>
</h1>

Correct: restructured to avoid the problem entirely

If you cannot separate interactive and non-interactive content, remove role="text" altogether.

<p>
  For more details, visit
  <a href="/about">our about page</a>.
</p>

The key principle is straightforward: role="text" is meant for presentation of static text only. Never place links, buttons, inputs, or any other focusable element inside it.

Help us improve our guides

Was this guide helpful?

Detect accessibility issues automatically

Rocket Validator scans thousands of pages with Axe Core and the W3C Validator, finding accessibility issues across your entire site.

Ready to validate your sites?
Start your free trial today.