Compatibility

Does obfuscation break accessibility?

The transforms — renaming, string tables, control-flow rewriting — cannot reach the accessibility tree, and the answer for those is a clean no. The interesting part of this question is elsewhere: two runtime-defense options cause genuine accessibility problems, and one of them degrades the experience for every visitor on the site.

Why the transforms cannot touch it

Assistive technology does not read your JavaScript. It reads the accessibility tree, which the browser derives from the DOM: element roles, ARIA attributes, label text, heading structure, focus order. Obfuscation rewrites identifiers — the names of variables and functions — and identifiers appear nowhere in that tree.

The second half of the answer is about strings, and it is the half people doubt. Protection preserves string values. Moving a literal into a lookup table or encoding it changes how the string is stored in the file, not what the expression evaluates to at runtime. So all of this survives unchanged:

  • el.setAttribute("aria-expanded", "true") — both arguments are strings.
  • el.setAttribute("aria-label", t("close_dialog")) — the key and the translated result are string values.
  • role, aria-live, aria-describedby and every other attribute written in your markup, which protection never opens.
  • Element IDs referenced by aria-labelledby, CSS class names toggled from JavaScript, and data- attributes — strings, all of them.

This is the same reason end-to-end selectors based on ARIA roles and visible text keep passing after protection while selectors reaching into internals break. Accessibility lives on the public surface, and the public surface is what protection is built to preserve.

The option that actually causes harm

BlockDevToolsKeys is the one to look at before anything else. It intercepts F12, Ctrl+U and the Ctrl+Shift combinations — and it also registers a global contextmenu handler that calls preventDefault() on every right-click anywhere in the page.

That last part is the problem. The context menu is not a developer feature. Keyboard users open it with the Menu key or Shift+F10, and it is where copy, paste, open-in-new-tab, spell-check, translation and several assistive-technology affordances live. Suppressing it removes all of that from everyone, in exchange for closing one of roughly eight routes to bytes the browser has already finished downloading. The keyboard interception raises a related question against the criterion that all functionality be operable from a keyboard.

The recommendation is straightforward and it is the same one the devtools article reaches from the security side: leave it off. It is a speed bump for the incurious, priced in permanent usability loss for people who did nothing wrong.

The option that causes false alarms

AntiMonkeyPatching is more subtle and much more defensible — it just needs configuring around the accessibility stack.

The option snapshots selected browser APIs at startup and checks them on a heartbeat, reporting the first replacement it detects through your configured runtime-defense action. The monitored set includes event registration, timers, Fetch, XHR, Promise, storage and Web Crypto. Now consider what an accessibility overlay does, or an assistive browser extension, or an observability agent: it replaces exactly those APIs, on purpose, to observe or modify behaviour. From the guard's perspective that is indistinguishable from tampering.

The documented answer is to exclude the specific paths rather than to disable the feature. AntiMonkeyPatchingExcludeGlobals takes comma or newline separated dotted API paths and drops them from monitoring. Where the patching happens before your protected bundle starts — which is typical for an extension — the clean-realm comparison is what flags it, so AntiMonkeyPatchingCleanRealm is the switch to reconsider. The documentation is explicit that these are same-origin browser signals rather than a trust root, and that you should test with your real extensions and observability stack before release. Accessibility tooling belongs on that test list.

One consequence worth planning for: if you sell to enterprises or the public sector, some of your users will be running an overlay you have never heard of, mandated by their employer. You cannot enumerate those in advance. Choosing a runtime-defense action that degrades rather than one that throws or blanks the page means an unexpected patch produces a reduced experience instead of a blank screen for the user least able to work around it.

Performance, which is the quiet one

Protected code costs cycles, most visibly where control-flow work or string-table lookups land on a hot path. A screen reader, magnifier or speech-recognition engine is a second process competing for the same CPU, frequently on hardware chosen for cost rather than speed.

The symptoms are the ones accessibility work already watches for: focus arriving late, aria-live regions announcing behind the change they describe, and interaction handlers missing their frame budget so a control feels unresponsive. None of this is caused by obfuscation specifically — it is the general overhead described in the bundle-size and performance article — but it lands hardest on the users with the least headroom. Measure on representative hardware with assistive technology actually running, and consider a lower preset on the code paths that drive interaction while keeping maximum strength on the logic worth protecting.

How to test it

Split it the same way the test pipeline splits, and for the same reason.

  • Automated scans on the unprotected build. axe, Lighthouse and friends inspect the rendered DOM, so results are identical either way — but on the unprotected build every finding points at real source, which is the difference between a fix and an investigation.
  • Manual passes on the protected artifact. Keyboard-only navigation, a screen-reader walkthrough of the primary flows, focus management through dialogs and route changes. This is the build you ship, so this is the build that has to pass.
  • One deliberate context-menu check. Right-click, and press Shift+F10. If nothing happens, BlockDevToolsKeys is on.
  • One run with an overlay or assistive extension installed. This is what catches the anti-monkey-patching interaction before a customer does, and it takes ten minutes.

If something does break and you cannot see why, build once with --formatted-output. Protected code that is merely unreadable becomes protected code you can set a breakpoint in, which turns a vague report into a line number. It is a diagnostic build, never a shipping one.

The short version

The transforms are fine. ARIA attributes, roles, labels and every string your interface speaks come through protection unchanged, because they live in markup and string values rather than in identifiers. The accessibility risk in a protection configuration is concentrated in two runtime-defense options: turn BlockDevToolsKeys off, because it suppresses the context menu for everyone and buys almost nothing, and configure AntiMonkeyPatching with exclusions so an accessibility overlay is not mistaken for an attacker. Then test the protected build with a keyboard and a screen reader, which is what you should be doing regardless of whether anything is obfuscated.

Frequently asked questions

Does obfuscation break screen readers?

Not by itself. A screen reader reads the accessibility tree, which the browser builds from your markup — element roles, ARIA attributes, label text and semantic structure. Identifier renaming rewrites variable and function names in JavaScript, which are not part of that tree and are never exposed to assistive technology. Label text set from JavaScript is a string value, and string values are preserved: moving a literal into a lookup table or encoding it changes how it is stored, not what it evaluates to.

Do ARIA attributes and roles survive obfuscation?

Yes. Attributes such as aria-label, aria-describedby, aria-live and role live in HTML, and protection operates on JavaScript. Code that sets them at runtime does so through string arguments — setAttribute('aria-expanded', 'true') passes two strings — and those strings come through protection intact. The same holds for data attributes, CSS class names applied from JavaScript, and element IDs referenced by aria-labelledby, all of which are string values rather than identifiers.

Why did my accessibility overlay stop working after I enabled runtime defense?

Almost certainly AntiMonkeyPatching. That option snapshots selected browser APIs — including event registration, timers, Fetch and XHR — and reports the first replacement it detects through your configured failure action. Accessibility overlays, some assistive browser extensions and instrumentation agents work precisely by replacing those APIs, so an intentional patch reads as tampering. The documented fix is to exclude the specific dotted API paths through AntiMonkeyPatchingExcludeGlobals, or to disable AntiMonkeyPatchingCleanRealm when the patching happens before your bundle starts.

Does blocking developer-tools keys cause accessibility problems?

Yes, and this is the option to look at first. BlockDevToolsKeys registers a global contextmenu handler that calls preventDefault on every right-click anywhere in the page, alongside intercepting F12, Ctrl+U and the Ctrl+Shift combinations. Suppressing the context menu removes a route that keyboard users reach with the Menu key or Shift+F10, and it takes copy, paste, open-in-new-tab, spell-check and translation with it. The security value is close to zero because the bytes are already downloaded, so the cost lands on your users and not on anyone you were worried about.

Should I run accessibility tests against protected or unprotected builds?

Both, for different purposes. Automated tools such as axe or Lighthouse inspect the rendered DOM and accessibility tree, so they give the same findings either way, and running them on the unprotected build makes remediation easier because the stack traces point at real source. But your final manual pass — keyboard navigation, screen-reader walkthrough, focus management — belongs on the protected artifact, for the same reason end-to-end tests do: it is the only build that exercises the bytes you actually ship.

Can protected code be slow enough to hurt assistive technology?

It can, on low-end hardware. Protected output carries real overhead where control-flow transforms or string-table lookups sit on a hot path, and a screen reader or magnifier is another process competing for the same CPU. The symptoms are the ones accessibility work already cares about: delayed focus, live regions announcing late, and interactions that miss their frame budget. Measure on representative hardware with assistive technology running rather than on a developer laptop, and step the preset down on the code paths that drive interaction.

Related reading