-Web-Accessibility-Widget: Web Accessibility Widget: A Tiny State Machine for Any Website

A vanilla JavaScript overlay that rewrites contrast, typography, and motion with one apply() loop, a few CSS classes, and no framework at all.

6 to 8 min read • View on GitHub • More from That-ASHWIN

A dense website on the left is overlaid by a small control panel that changes the whole page on the right. The scene explains how a lightweight widget can reshape readability without rebuilding the host site.
The project’s core idea is not the panel itself. It is the ability to flip a few host-page classes and change the whole reading experience.
Key Takeaways

The smallest possible accessibility layer

The first thing to notice is what this repo does not try to be. It does not rebuild the site, and it does not hide behind a framework. It adds a small preference panel, then uses the browser’s own class system to reshape the page underneath it.

That makes the project feel less like a widget and more like infrastructure. The UI is just the front door. The real product is a reversible layer that can sit on top of someone else’s website without taking it over completely.

A close-up control room with one central dial labeled state sending lines to contrast, typography, dyslexia mode, grayscale, and motion reduction modules. The scene explains that the widget is a state-to-class translation layer rather than a collection of unrelated toggles.
The interesting part is not each toggle. It is the way one state object fans out into multiple host-page effects through a single apply step.

How the widget thinks

The technical heart is simple: load state, apply state, persist state. The widget reads from localStorage, stores preferences in a central object, and then maps those values onto the document root through classList.toggle() and a few direct style updates.

This diagram shows the actual logic chain. User intent becomes stored state, stored state becomes DOM classes, and DOM classes become visible changes on the host page.

const def = {
  contrast: false,
  dyslexia: false,
  grayscale: false,
  fontSize: 1,
  motion: true
};

let state = load() || { ...def };

function apply() {
  const html = document.documentElement;
  html.classList.toggle('a11y-contrast', state.contrast);
  html.classList.toggle('a11y-dyslexia', state.dyslexia);
  html.classList.toggle('a11y-grayscale', state.grayscale);
  html.classList.toggle('a11y-reduce-motion', !state.motion);
  html.style.setProperty('--a11y-font-size', state.fontSize + 'em');
  save(state);
}

function reset() {
  state = { ...def };
  apply();
}

That pattern is clean because it keeps the side effects in one place. The UI can change, the settings can grow, and the implementation still stays legible because there is a single translation point between state and behavior.

Why the CSS is doing the real work

The CSS is split into two jobs. One set of selectors styles the widget itself, with namespacing so it does not leak into the host page. The other set reaches outward, using high-specificity selectors and !important to override the site that already exists.

That split is the whole bargain. The widget behaves like a polite guest on the surface, then becomes forceful where it has to. It is a negotiation layer, not a decorative sidebar.

The result is a surprisingly practical pattern for any drop-in tool. Keep the chrome isolated. Make the effects global. Do not blur the boundary between the two.

The reset button is the tell

The reset logic reveals the project’s taste. Instead of patching each control back by hand, the code clones the default state and re-runs the same apply path. That is the software equivalent of a clean room reset: obvious, boring, and excellent.

This matters because the repo never pretends the state is magical. It treats preferences like data, not like scattered DOM accidents. That restraint is why the implementation is easy to trust.

What this repo is competing against

The broader category is messy. Commercial overlays promise automated accessibility, but they often arrive with opaque scripts, recurring fees, and a lot of distrust from accessibility professionals. Open-source widgets sit at the opposite end of the spectrum: lighter, clearer, and usually far less ambitious.

ApproachTransparencyPerformancePrivacyCostAccessibility philosophy
This repo and similar open-source widgetsSource is readable and behavior is easy to inspectSmall footprint and limited surface areaNo obvious need for tracking or analyticsFree to adoptAdds user preference controls without pretending to fix the whole site
Commercial overlay platformsOften proprietary and harder to auditHeavier scripts and more moving partsMay include analytics or vendor telemetryRecurring subscriptionMarkets automation as a shortcut to compliance
Native accessibility workBuilt into the site itselfUsually the best runtime outcomeDepends on implementation, not a vendor layerInternal engineering costFixes structure, semantics, and interaction at the source

The strongest case for this repo is not that it wins every comparison. It is that it tells the truth about its scope. It is a preference layer, not a remediation machine.

Where it fits in the real world

This kind of tool is most useful in institutions that need an immediate, low-friction way to give users control over readability. That includes legacy systems, under-resourced teams, and sites where a full redesign is not on the table yet.

In that setting, the widget is a pragmatic bridge. It gives people a better surface now while the slower work of fixing the underlying site continues. It should not be treated as a substitute for that work.

Use caseWidget layerNative remediation
Immediate readability controlsStrong fitPossible, but slower to ship
Legal or compliance claimsWeak fitMuch stronger fit
Long-term accessibility qualitySupportive onlyEssential
Low-friction deploymentVery strongDepends on site architecture

The limit of the overlay model

The cleanest conclusion is also the least flashy one. A widget can make a site more tolerable, more configurable, and more respectful of personal preferences. It cannot replace semantic markup, accessible components, or real remediation work.

That boundary is not a flaw. It is the point. The best version of this repo knows exactly what it is, and exactly what it is not.