A plug-and-play accessibility toolbar and assistive companion for the web, WCAG 2.1 AA/AAA and European Accessibility Act (EAA 2025) compliant, built as a native Web Component.
Zero dependencies. Zero build required. Ultra-lightweight (< 10 kB initial load). 100% GDPR & privacy-first (0 cookies, 0 telemetry). Agent-Ready.
π Live Demo & Documentation
In modern web development, teams looking to improve accessibility often find themselves stuck between three extremes:
| Solution Type | Examples | Strengths | Trade-offs | Where <a11y-control> Fits |
|---|---|---|---|---|
| Headless Primitives | React Aria, Radix UI, Base UI, Ark UI | Maximum design freedom | <a11y-control> provides a turnkey, pre-styled assistive suite in 1 line of HTML, framework-agnostic. |
|
| Component Libraries | shadcn/ui, HeroUI, Web Awesome | Complete UI kits (buttons, inputs) | <a11y-control> focuses purely on document-level assistive reading instruments (< 10 kB). |
|
| Commercial Overlays | UserWay, accessiBe | 1-line script tag | β 400β800 kB footprint, trackers, $490+/yr, high litigation risk for deceptive "instant waiver" claims | <a11y-control> is 100% Open Source (MIT), privacy-first, lightweight, and legally ethical. |
<a11y-control> is designed as an Assistive Reading Companion:
- Assistive Aid, Not an Overlay Waiver: Using
<a11y-control>directly satisfies mandatory user-personalization criteria under the European Accessibility Act (EAA 2025), RGAA 4.1, ADA Title III, and Section 508 (such as text resize, visual presentation, un-justified text, and text spacing). - Ethical Compliance: Unlike commercial overlay widgets that face severe legal sanctions for claiming "automatic legal indemnity",
<a11y-control>empowers users with genuine client-side assistive instruments without altering semantic underlying HTML maliciously. - Liability: Website owners remain responsible for ensuring their core markup is accessible. Use
window.a11y.audit()or professional audits to certify host document compliance.
Add a single script tag with data-auto-mount to your site's <head> or footer. The element automatically instantiates and mounts to document.body:
<script
type="module"
src="https://cdn.jsdelivr.net/npm/a11y-control"
data-auto-mount
data-lang="en"
data-position="bottom-right"
></script><script type="module" src="https://cdn.jsdelivr.net/npm/a11y-control"></script>
<a11y-control lang="en" position="bottom-right"></a11y-control>npm install a11y-controlimport 'a11y-control';<a11y-control lang="en" position="bottom-right"></a11y-control><a11y-control> is 100% SSR-safe and framework-agnostic.
'use client';
import { useEffect } from 'react';
export default function AccessibilityWidget() {
useEffect(() => {
import('a11y-control');
}, []);
return <a11y-control lang="en" position="bottom-right" />;
}---
// In your BaseLayout.astro
---
<a11y-control lang="en" position="bottom-right"></a11y-control>
<script>
import 'a11y-control';
</script><template>
<ClientOnly>
<a11y-control lang="fr" position="bottom-right" />
</ClientOnly>
</template>
<script setup>
import 'a11y-control';
</script>Paste right before </body> in your theme.liquid:
<script type="module" src="https://cdn.jsdelivr.net/npm/a11y-control" data-auto-mount data-lang="{{ request.locale.iso_code }}"></script>function add_a11y_control_script() {
echo '<script type="module" src="https://cdn.jsdelivr.net/npm/a11y-control" data-auto-mount></script>';
}
add_action('wp_footer', 'add_a11y_control_script');Because ES modules are deferred by modern browsers, a user with Dark Mode or Text Scaling enabled may see a momentary flash of unstyled content before the component hydrates.
Paste this tiny 2-line inline script into your <head> to restore saved preferences instantly before the first paint:
<script>
(function(){try{
var p=JSON.parse(localStorage.getItem('a11y-prefs')||'{}');
if(p.darkMode)document.documentElement.classList.add('a11y-dark-mode');
if(p.highContrast)document.documentElement.classList.add('a11y-high-contrast');
if(p.fontScale&&p.fontScale!==1)document.documentElement.style.fontSize=(p.fontScale*100)+'%';
}catch(e){}})();
</script><a11y-control> is 100% modular. You don't have to impose all 13 assistive tools on your users if some don't fit your website architecture or if you already provide your own features (e.g. an existing dark mode theme toggle).
| Attribute | Values | Default | Description |
|---|---|---|---|
lang |
"en" | "fr" | custom |
"en" |
Interface language (auto-detects from <html> or navigator.language) |
position |
"bottom-right" | "bottom-left" | "top-right" | "top-left" |
"bottom-right" |
Screen corner for the floating trigger button |
features |
Comma-separated keys | undefined (all) |
Whitelist mode: display only the listed tools |
exclude |
Comma-separated keys | undefined (none) |
Blacklist mode: display all tools except the listed ones |
| Key | Section | Description |
|---|---|---|
fontSize (or fontScale) |
Typography | Stepper from 80% to 200% with live screen reader readouts |
highContrast |
Display | High contrast black background, white text, yellow links |
grayscale |
Display | Monochrome grayscale filter |
highlightLinks |
Display | High-visibility underlines and outline halos on interactive links |
bigCursor |
Display | High-contrast enlarged cursor |
dyslexiaFont |
Reading & Focus | OpenDyslexic specialized typeface |
textSpacing |
Reading & Focus | WCAG 1.4.12 letter, word, and line spacing override |
alignLeft |
Reading & Focus | Eliminates text justification and hyphenation |
readingGuide |
Reading & Focus | Horizontal reading ruler tracking pointer position |
readingMask |
Reading & Focus | Dimmed screen overlay with clear focal slit for ADHD & focus |
reduceMotion |
Reading & Focus | Disables transitions and animations (0.001ms) |
speechSynthesis (or speech) |
Voice & Tools | Web Speech API audio reader with karaoke streaming dock |
darkMode |
Theme | Deep dark theme |
Avoid duplicate theme switchers by simply excluding darkMode:
<a11y-control exclude="darkMode"></a11y-control><a11y-control exclude="darkMode, grayscale, readingMask"></a11y-control>Display only text scaling, dyslexia font, text spacing, and the reading guide:
<a11y-control features="fontSize, dyslexiaFont, textSpacing, readingGuide"></a11y-control>Provide an on-demand Text-to-Speech tool without extra visual toggles:
<a11y-control features="speechSynthesis"></a11y-control>Because features and exclude are observed attributes (observedAttributes), <a11y-control> automatically and instantly re-renders its panel whenever you update them in JavaScript β zero reload required:
const a11y = document.querySelector('a11y-control');
// Dynamically hide dark mode
a11y.setAttribute('exclude', 'darkMode');
// Or switch to a minimal whitelist
a11y.setAttribute('features', 'fontSize, highContrast');
// Clear filters to restore all 13 tools
a11y.removeAttribute('exclude');
a11y.removeAttribute('features');To maintain technical integrity, <a11y-control> strictly separates genuine assistive presentation overrides from ergonomic comfort and simulation tools:
| Control | Effect on Document | Addressed Criterion | Level |
|---|---|---|---|
| π‘ Font Size | Scales root typography (80% β 200%) via rem baseline with aria-live announcements |
1.4.4 Resize Text | AA |
| π Text Spacing | Sets line-height: 1.6, letter-spacing: 0.12em, word-spacing: 0.16em | 1.4.12 Text Spacing | AA |
| π Align Left | Eliminates text justification and hyphens to remove distracting white rivers | 1.4.8 Visual Presentation | AAA |
| βΈ Reduce Motion | Sets transitions/animations to 0.001ms, pauses HTML5 videos and Web Animations | 2.3.3 Animation from Interactions | AAA |
| β High Contrast | Forces high-contrast palette (black background, white text, yellow links) | 1.4.6 Contrast Enhanced | AAA |
| π Highlight Links | Applies bold underlines and contrasting outline halos to interactive links | 1.4.1 Use of Color | A |
| ποΈ Text to Speech | Web Speech API audio selection with voice selector and synchronized karaoke dock | 1.2.1 Audio-only / Cognitive | A |
Note
Typography Scaling vs Native Browser Zoom: The font scaler adjusts the document's root font size (html { font-size: X% }), which scales typography across designs built with relative units (rem, em). Users who prefer full-page raster/layout zoom can continue using their browser's native zoom (Cmd/Ctrl + +/-), which is fully supported and unhindered.
| Feature | Category | Purpose |
|---|---|---|
| β¬ Monochrome / Grayscale | Simulation & Visual Aid | Desaturates document (filter: grayscale(100%)). Useful for developers to test information hierarchy without color (WCAG 1.4.1 verification) and for users with severe photophobia. Note: Grayscale does not substitute for 1.4.11 non-text contrast ratios. |
| T Dyslexia-Friendly Font | Cognitive Comfort | Applies a resilient dyslexia-optimized font stack ('OpenDyslexic', 'Comic Sans MS', 'Lexend', Arial, sans-serif). Zero external network requests by default (100% CSP safe). |
| β Reading Guide | Focal Tracking | Ruler guide bar smoothly tracking pointer Y position for cognitive tracking (ADHD). |
| π² Reading Mask | Focal Concentration | Dimmed screen overlay with a 76px clear focal slit to isolate reading lines. |
| π― Big Cursor | Motor & Low Vision | Universal 32x32px high-visibility cursor with crisp white border (encoded as base64 PNG for universal browser security). |
| π Dark/Light Mode | Photophobia Comfort | Deep obsidian theme preserving photography & media contrast. Devs can override via html.a11y-dark-mode. |
Preferences are automatically saved in localStorage and respect OS preferences (prefers-color-scheme, prefers-reduced-motion, prefers-contrast: more, and forced-colors: active) on first visit.
Tip
Performance Architecture (< 10 kB Initial Load):
To preserve maximum speed for all users, the complete SpeechSynthesis engine (src/speech.js) and its styles are dynamically lazy-loaded on demand (import('./speech.js')) only when the user turns on Text-to-Speech (or if restored from localStorage). The initial core bundle is under 10 kB after minification (Brotli/Gzip). Source files are shipped unminified β minify with your own bundler or npx terser src/a11y-control.js ... -o dist/a11y-control.min.js.
<a11y-control> is designed to achieve 100% WCAG AAA conformance:
- W3C APG Modal Dialog Pattern: Declares
role="dialog",aria-modal="true",aria-label, andaria-expandedon the trigger. - Strict Focus Trap & Restoration: Focus automatically lands on
#close-btnupon opening. PressingTab/Shift+Tabcycles strictly inside the dialog. Closing restores focus to the trigger button. - Emergency Escape: Pressing
Escapecloses the panel, halts any active speech synthesis, and returns focus. - Semantic Heading Navigation (WCAG 1.3.1): Section dividers use semantic
<h3>headings so screen reader users can jump directly from group to group using the H key. - Enhanced Switch Contrast (WCAG 1.4.11): Switches feature a
1.5pxborder with > 3:1 contrast ratio against the background, even when turned off. - Accessible Inputs: All toggles use native
<input type="checkbox" role="switch">linked to<label>elements, operable via bothSpaceandEnter.
<a11y-control> registers its active instance on window.a11y:
const a11y = document.querySelector('a11y-control') || window.a11y;
// Programmatic panel control
a11y.open();
a11y.close();
a11y.toggle();
// Get & Set preferences
a11y.setPref('textSpacing', true);
a11y.setPref('fontScale', 1.3);
const prefs = a11y.getPrefs();
// Reset all preferences
a11y.reset();
// Automated DOM Accessibility Audit
const report = a11y.audit();
console.log(report);
// { issuesCount: 2, missingAlt: 1, unlabeledInputs: 1, emptyButtons: 0, details: [...] }
// Extend with custom translations
import { A11yControl } from 'a11y-control';
A11yControl.registerLocale('es', {
triggerLabel: 'Ajustes de accesibilidad',
title: 'Accesibilidad',
close: 'Cerrar',
// ...
});Events bubble and cross the Shadow DOM barrier (composed: true):
// React to any setting change (ideal for analytics & app stores)
window.addEventListener('a11y-change', (e) => {
console.log('Modified key:', e.detail.key);
console.log('New value:', e.detail.value);
console.log('Full preferences:', e.detail.prefs);
});
// Panel visibility events
window.addEventListener('a11y-open', () => console.log('Panel opened'));
window.addEventListener('a11y-close', () => console.log('Panel closed'));
window.addEventListener('a11y-reset', (e) => console.log('Reset:', e.detail.prefs));All visual tokens are exposed as CSS custom properties on the <a11y-control> element:
a11y-control {
--a11y-accent: #005fcc; /* Primary accent (buttons, focus rings) */
--a11y-accent-hover: #0047a3;
--a11y-bg: #ffffff; /* Panel background */
--a11y-surface: #f5f5f5; /* Surface / hover background */
--a11y-border: #d0d0d0;
--a11y-text: #1a1a1a;
--a11y-text-muted: #555555;
--a11y-radius: 12px;
--a11y-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
--a11y-transition: 0.18s ease;
}You can use any CSS class or attribute selector on <a11y-control> to change its appearance without touching the source β the custom properties cascade into the Shadow DOM automatically:
<a11y-control class="my-brand" lang="en"></a11y-control>/* Override accent and background for your brand */
a11y-control.my-brand {
--a11y-accent: #e63946;
--a11y-bg: #1a1a2e;
--a11y-text: #eaeaea;
}
/* Reposition or resize the floating trigger button */
a11y-control.my-brand {
--a11y-trigger-size: 56px; /* Default: 52px */
}The floating trigger button exposes a CSS Part for fine-grained external styling without needing Shadow DOM piercing:
/* Style the floating accessibility button */
a11y-control::part(trigger) {
background: #e63946;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(230, 57, 70, 0.4);
}Note
Big Cursor implementation: The high-visibility cursor is encoded as a base64 PNG (data:image/png;base64,...) instead of SVG. This is intentional β SVG data URIs for cursor are blocked by most browsers for security reasons. The PNG approach guarantees universal compatibility across Chrome, Firefox, Safari, and Edge.
These classes are toggled directly on the root element, so your own CSS can react to them freely:
/* Example: apply your own dark palette when the user enables dark mode */
html.a11y-dark-mode .hero { background: #0d1117; }
html.a11y-text-spacing article { max-width: 65ch; } /* Give breathing room */| Class | Triggered by |
|---|---|
html.a11y-high-contrast |
High Contrast toggle |
html.a11y-grayscale |
Grayscale toggle |
html.a11y-dyslexia |
Dyslexia Font toggle |
html.a11y-text-spacing |
Text Spacing toggle |
html.a11y-align-left |
Align Left toggle |
html.a11y-big-cursor |
Big Cursor toggle |
html.a11y-reduce-motion |
Reduce Motion toggle |
html.a11y-highlight-links |
Highlight Links toggle |
html.a11y-dark-mode |
Dark Mode toggle |
<a11y-control> is designed for modern autonomous development environments:
_agent/skills/accessibility-integration: Pre-packaged Agent Skill for Cursor, Antigravity, Claude Code, and Windsurf instructing AI assistants how to integrate and maintain compatibility.llms.txt: Machine-readable context manifest located at the root for instant LLM ingestion.- Machine-Readable DOM State: Root element carries
data-a11y-stateattribute with serialized JSON preferences. - Tool Calling Ready: JSON schema provided in
llms.txtfor chatbot/voice assistant integrations. - TypeScript Definitions: Complete
.d.tsdefinitions included insrc/a11y-control.d.ts.
<a11y-control> is engineered to satisfy enterprise procurement and compliance audits:
| Audit Dimension | Evaluation | Technical Guarantee |
|---|---|---|
| European Accessibility Act (EAA 2025/2026) | β Meets Personalization Criteria | Provides mandatory text resizing (1.4.4), un-justification (1.4.8), spacing (1.4.12), and contrast (1.4.6). |
| RGAA 4.1 & BITV 2.0 | β Opposable Conformance | Directly implements client presentation adjustments required by French and German administrative criteria. |
| ADA Title III & Section 508 | β Safe Assistive Companion | No false "automatic compliance waivers". Pure client-side assistive instrument companion. |
| GDPR / ePrivacy Directive | π‘οΈ 100% Compliant | Zero cookies, zero telemetry, zero analytics. User preferences reside strictly in local localStorage. |
| Content Security Policy (CSP) | β‘ Strict CSP Safe | Zero dynamic external script execution. Air-gapped and intranet environment ready. |
| Core Web Vitals Impact | π Zero Regression | Initial core transfer < 10 kB. Text-to-Speech audio engine is lazy-loaded on demand. |
<a11y-control> is an open-source, framework-agnostic native Web Component that injects a high-performance, WCAG 2.1 AA/AAA compliant accessibility toolbar into any web page with zero dependencies.
React Aria and Radix UI are headless primitive building blocks reserved exclusively for React applications: they provide unstyled logic (hooks/primitives) that require developers to design, code, and test their own UI from scratch. In contrast, <a11y-control> is a drop-in assistive companion toolbar with a turnkey, fully-styled Shadow DOM interface that works across any tech stack (React, Vue, Astro, Shopify, WordPress, or Vanilla HTML).
Yes. Unlike commercial overlay widgets that inject 500 kB+ of proprietary trackers, charge expensive annual subscriptions, and face legal lawsuits for claiming "automated ADA compliance", <a11y-control> is 100% free and open source (MIT), lightweight (< 10 kB), strictly respects user privacy (0 cookies), and provides authentic user-driven accessibility enhancements without deceptive legal promises.
Yes. <a11y-control> is built with SSR-safe checks (typeof HTMLElement !== 'undefined'). In Next.js (App Router or Pages Router), simply load it within a client component or via dynamic import, without any server-side hydration mismatches.
Simply add a single <script> tag with the data-auto-mount attribute to your HTML document:
<script type="module" src="https://cdn.jsdelivr.net/npm/a11y-control" data-auto-mount></script>The component automatically mounts to document.body on page load.
MIT β feel free to use, modify, and distribute.