A zero-dependency accessibility toolbar you can drop into any website with one
<script>tag: text scaling, high contrast, reading comfort, motion pause, link underlining and optional VLibras (Brazilian Sign Language) — every feature mapped to WCAG 2.2, eMAG 3.1 and ABNT NBR 17225:2025.
Born from real accessibility-audit work at UFRJ (EMAR — student monitors for digital accessibility, DIRAC): auditing a public-sector website, we kept finding the same anti-patterns in "accessibility menu" plugins — font resizing that loops over every DOM node and then reloads the page, contrast buttons without accessible names, keyboard shortcuts that scroll the view but never move focus. a11ybar is the native, standards-first alternative we wished existed.
<script>
window.A11ybarConfig = { lang: "pt-BR", position: "bottom-right", vlibras: true };
</script>
<script src="a11ybar.js"></script>That's it — no build step, no framework, no CSS file. Try the live demo →
| Button | What it does | Grounded in |
|---|---|---|
A− / A+ |
Text scaling via one CSS custom property on :root (no per-element loop, no reload) |
WCAG 1.4.4 Resize Text · eMAG rec. 28 |
| ◐ | High contrast — curated eMAG-style palette (black bg 21:1, cyan links 16.7:1, yellow controls 19.6:1) + yellow :focus-visible everywhere; media keeps real colours |
WCAG 1.4.3/1.4.6 Contrast · 2.4.7 Focus Visible · eMAG 4.1 |
| ≡ | Reading comfort: applies the WCAG text-spacing minimums (line 1.5+, letter .12em, word .16em) | WCAG 1.4.12 Text Spacing · dyslexia guidance |
| ⏸ | Pauses all CSS animations/transitions/smooth-scroll | WCAG 2.2.2 Pause, Stop, Hide · 2.3.3 Animation from Interactions · GAIA (autism) |
| ⎁ | Underlines every link — colour is never the only cue | WCAG 1.4.1 Use of Color |
| 🤟 | Loads the official VLibras widget on demand (opt-in) | Lei 13.146/2015 (LBI) · eMAG |
| ↺ | Restores defaults | — |
The toolbar itself is accessible — that's the point:
role="toolbar"with a properaria-label, following the ARIA APG toolbar pattern (roving tabindex: ←/→/Home/End navigate, one Tab stop).- Every toggle exposes
aria-pressedstate; every button has an accessible name. - Targets are ≥ 44×44 px (WCAG 2.5.5/2.5.8) with a strong
:focus-visibleindicator (WCAG 2.4.7). - State changes are O(1) class flips on
<html>— no page reload, scroll position preserved. - Preferences persist in
localStorage; on first visit,prefers-reduced-motionis honoured automatically (WCAG 2.3.3).
window.A11ybarConfig = {
lang: "pt-BR", // "pt-BR" | "en"
position: "bottom-right", // top-right | top-left | bottom-right | bottom-left
vlibras: false // show the VLibras (Libras translation) button
};
// manual mode: set window.A11ybarManual = true and call a11ybar.init(config) yourselfPreserving meaningful colours in contrast mode: the high-contrast palette forces backgrounds to black (like OS high-contrast modes do). Elements whose colours carry information — charts, colour swatches, status indicators — can opt out with the data-a11ybar-keep attribute:
<canvas id="grafico-vendas" data-a11ybar-keep></canvas>- Text scaling follows sites that size text in
rem/%(best practice); fixedpxtypography won't scale — that's a bug in the page, and a11ybar won't paper over it with DOM-walking hacks. - High contrast forces a black/white/cyan/yellow palette with
!important— deliberate (it must win over any page CSS), but a palette hand-tuned per-site is always superior when you control the stylesheet. No CSSfilteris used: filters on the root element breakposition:fixedwidgets (including VLibras) and wash colours out. - VLibras loads an external government script — hence opt-in.
12 behavioural tests (vitest + jsdom) cover the ARIA structure, font scaling, aria-pressed state, persistence, prefers-reduced-motion and the roving-tabindex keyboard pattern:
npm install
npm test- npm package + CDN build
- Sister project: an eMAG/ABNT-aware audit CLI that generates instructional reports in the format Brazilian public institutions actually need.
MIT — © Luiz Felipe Cantanhede Cristino.
