Accessibility overlay screen reader conflicts are real and measurable at the DOM level. This post explains what overlays inject, where ARIA collisions occur, and what automated tooling can and cannot tell you.
Overlay vendors — accessiBe, UserWay, and similar — market their products as compatible with NVDA, JAWS, and VoiceOver. The pitch is that a single JavaScript bundle, loaded after the page, will remediate the DOM in real time and produce an experience that works for screen reader users. What actually happens is more complicated. The bundle injects ARIA attributes, wraps elements in new containers, and toggles visibility flags on a heuristic schedule — on top of whatever the site's own markup already says. When those two layers disagree, screen readers get contradictory signals.
What overlays inject at runtime
Accessibility overlays work as late-binding DOM patches. After the browser renders the page, the overlay script walks the tree and applies a set of heuristic transforms: adding aria-label to elements it judges as unlabeled, assigning role values to generic containers, inserting synthetic skip links, and wrapping sections in landmark boundaries it deems missing. The overlay's own toolbar — a floating settings button, a preferences panel — also lands in the DOM and registers as interactive content.
Each of these changes is additive or overriding. The overlay does not negotiate with the existing markup — it sets what it believes is correct and moves on. If the site already expressed something semantically, the overlay may reinforce it, contradict it, or create a duplicate. Whether any of those outcomes is better or worse depends on which specific rule fired and on which screen reader is reading the result.
Where ARIA conflicts arise
The most common failure mode is aria-hidden mismanagement. Overlays sometimes set aria-hidden="true" on sections they judge as decorative or visually redundant — a repeated navigation block, a decorative banner. The intent is to suppress it from the screen reader tree. The problem is that aria-hidden does not suppress keyboard focus. A keyboard user can still tab into a focusable element inside that section; a screen reader user following along hears nothing announced for controls they land on. The element is reachable but invisible to assistive technology.
A second pattern is role duplication. If the site already marks a nav element with role="navigation", and the overlay wraps that same element inside a container also carrying role="navigation", some screen reader versions announce the landmark label twice or expose a nested landmark that the document outline never intended. The structural model the AT user is navigating no longer matches the visual page.
<!-- site's own markup: role already explicit -->
<nav aria-label="Main navigation">
<ul>…</ul>
</nav>
<!-- overlay injection: outer container adds a second landmark -->
<div role="navigation" aria-label="Main navigation (enhanced)">
<nav aria-label="Main navigation">
<ul>…</ul>
</nav>
</div>
<!-- Screen readers now see two nested "navigation" landmarks.
NVDA and JAWS may announce "navigation" on entry to the outer div
and again on entry to the inner nav, confusing the document outline. -->A third pattern is aria-live region injection. Overlays sometimes insert live regions to announce their own status messages — "accessibility features activated," "contrast mode on." If the site also uses live regions for application state, two announcement streams compete. Screen readers queue announcements; a high-priority overlay message can interrupt or displace application feedback the user was waiting for.
What axe-core catches — and what it does not
axe-core is a DOM and ARIA rule engine from Deque. It parses the accessibility tree as the browser exposes it and checks whether attributes satisfy WCAG success criteria. Against the conflict patterns above, axe-core will catch: aria-hidden set on a focusable element (aria-hidden-focus rule), invalid role values (aria-roles), duplicate ARIA IDs used on labeled controls (duplicate-id-aria), and aria-required-children violations on composite widgets. These are structural conditions that strongly correlate with screen reader problems.
axe-core does not operate a screen reader. It has no model of announcement order, virtual cursor movement, or AT version behavior. NVDA 2024.1, JAWS 2025, and VoiceOver on macOS 15 can respond differently to the same DOM state — sometimes navigating through it cleanly, sometimes falling into a silence loop. axe-core gives you a consistent, reproducible structural signal. Real AT testing is a separate, manual step that answers a different question.
What this means in practice: a clean axe-core run does not certify that a screen reader user will have a usable experience. But a failing axe-core run — especially one where violations appear only after the overlay loads — is direct evidence that the overlay introduced a structural problem. That is a defensible, timestamped observation about the DOM conditions under which an AT user would encounter the page.
How OverlayRiskWitness surfaces DOM-level evidence
OverlayRiskWitness loads the page twice in a real browser using Browserbase — a hosted Chromium session that mirrors production network conditions. The first pass blocks the overlay at the network layer, so axe-core sees the site as it ships without intervention. The second pass loads the same URL with the overlay active and waits for it to finish injecting. Same viewport, same rule set, same axe-core version — only the overlay's presence differs.
The diff is computed per rule. A rule that had zero violations in the first pass and has violations in the second pass means the overlay introduced the condition — the DOM was structurally sound without it and became structurally unsound with it. That transition is the highest-signal finding the tool produces for screen reader conflicts: the overlay made the ARIA state worse.
Reading the transitions for ARIA-specific rules
Not every rule is equally relevant to screen reader conflicts. The rules to watch most closely in a before/after diff are the ones that govern how a screen reader constructs the accessibility tree and navigates it. In the transition matrix, filter for these rule ids and look at the direction of change.
- aria-hidden-focus — flags a focusable element inside an aria-hidden container. Introduced by overlay: strong screen reader conflict indicator.
- duplicate-id-aria — two elements share the same ID used as an aria-labelledby target. Overlay generates IDs programmatically and can collide with existing ones.
- aria-roles — invalid role value on an element the overlay annotated. Catches typos and unsupported role names in the injected layer.
- aria-required-children — a composite widget (listbox, menu, grid) the overlay wrapped is now missing expected child roles.
- aria-valid-attr-value — aria-live, aria-relevant, or aria-atomic set to a value the browser does not recognize. Overlay live-region injections sometimes use non-spec values.
A finding state of "did not hold up" on any of these rules — where the overlay was on and the rule failed — is evidence that the overlay's injection degraded the semantic structure AT users rely on. The finding state of "not testable" on a rule means the check could not evaluate the condition in one pass; that is a gap in evidence, not a clean bill of health.
If you need a rule-by-rule framework for separating what a witness run can verify from what still needs a manual pass, use our WCAG 2.2 AA checklist for sites running an accessibility overlay. It maps the overlay-on/off diff back to the principles teams usually cite in their accessibility statements.
AccessiBe and UserWay both publish claims about screen reader compatibility in their marketing copy and in the accessibility statements they generate for customer sites. When a witness run surfaces a rule that moved from pass to violation after the overlay loaded, that gap between the published claim and the observed DOM state is the evidentiary core of a "did not hold up" finding.
What to do with this evidence
A witness run produces observations. What you do with them depends on your role. Here is how the evidence maps to action for the most common audiences.
- Engineering team: use the rule ids and node selectors in the diff to find the exact DOM nodes the overlay is touching. Decide whether the fix belongs in your markup or in a configuration change to the overlay.
- Compliance or legal counsel: the timestamped before/after diff is the factual basis for assessing whether the site's published accessibility statement can be defended. The tool does not provide legal advice; it provides the evidence counsel needs to do that assessment.
- Accessibility consultant: the transition matrix is a starting point for a manual AT test session. Rules that regressed with the overlay on tell you exactly where to focus your NVDA or VoiceOver walkthrough.
- Agency or third-party auditor: the Risk Packet ($49) contains the full diff across 5–10 pages, with each finding cross-referenced to the claim it relates to. The Drift Monitor ($99/month) re-runs the witness on a schedule and alerts you when a transition changes between runs.
- Overlay vendor evaluation: running the witness on a page before and after installing a new overlay version lets you measure whether a version update improved, worsened, or had no effect on each rule — vendor-neutral, reproducible.
The free single-page witness at overlayrisk.com surfaces the first finding without a signup wall. If the page you test has an overlay active, the first finding will show you the overlay vendor detected, the transition direction on the highest-priority rule, and the node selector where the issue lives. That is enough to know whether a deeper investigation is warranted before you commit to a full packet or a monitoring subscription.
The OverlayRiskWitness engineering team builds the two-pass witness runner, the axe-core diff pipeline, and the Risk Packet composer. Every post is grounded in what the engine actually observes on live pages.