Skip to content

pigmilcom/a11y

Repository files navigation

@pigmilcom/a11y

About Simple, lightweight accessibility widget that enhances usability and adds control features to any website instantly. Zero dependencies. WCAG 2.1 Ready. Drop in one <script> tag or install via npm — visitors get instant control over text size, contrast, colour filters, motion, and more. Preferences persist via localStorage.


CDN — Plug & Play

No React, no npm, no build step. Add one tag to your <head>.

jsDelivr (recommended)

Served from the npm registry via jsDelivr's global edge network — always the latest published version:

<script
  src="https://cdn.jsdelivr.net/npm/@pigmilcom/a11y/dist/a11y.cdn.js"
  data-position="bottom-right"
></script>

Pin to a specific version:

<script
  src="https://cdn.jsdelivr.net/npm/@pigmilcom/a11y@1.0.1/dist/a11y.cdn.js"
  data-position="bottom-right"
></script>

Self-hosted (pigmil CDN)

Use your own CDN endpoint for full control over deployment:

<script
  src="https://cdn.pigmil.com/a11y/dist/a11y.cdn.js"
  data-position="bottom-right"
></script>

The widget auto-mounts on DOMContentLoaded. React 18 and all CSS are bundled inside — nothing else needed.

data-position values

Value Placement
bottom-right Bottom-right corner (default)
bottom-left Bottom-left corner
top-right Top-right corner
top-left Top-left corner

data-theme values

Value Behaviour
omitted / auto Matches <html class="dark"> or color-scheme: dark; otherwise light
light Always use the light theme
dark Always use the dark theme

data-lang values

Value Language
en English (default)
es Spanish
fr French
de German
pt Portuguese
zh Chinese (Simplified)
ar Arabic
hi Hindi

Language resolution works like this:

  1. If data-lang or the React lang prop is provided, that language is used and saved to localStorage['a11y-lang'].
  2. If data-lang / lang is omitted, the widget reads localStorage['a11y-lang'].
  3. If localStorage['a11y-lang'] does not exist yet, the widget defaults to 'en' and saves it.

This means the widget language can be changed dynamically by updating localStorage['a11y-lang'].

<!-- Default — follows the page's html theme, reads a11y-lang from localStorage, falls back to en -->
<script
  src="https://cdn.jsdelivr.net/npm/@pigmilcom/a11y/dist/a11y.cdn.js"
  data-position="bottom-right"
></script>

<!-- Equivalent explicit auto mode -->
<script
  src="https://cdn.jsdelivr.net/npm/@pigmilcom/a11y/dist/a11y.cdn.js"
  data-position="bottom-right"
  data-theme="auto"
></script>

<!-- Force light theme -->
<script
  src="https://cdn.jsdelivr.net/npm/@pigmilcom/a11y/dist/a11y.cdn.js"
  data-position="bottom-right"
  data-theme="light"
></script>

<!-- Force dark theme -->
<script
  src="https://cdn.jsdelivr.net/npm/@pigmilcom/a11y/dist/a11y.cdn.js"
  data-position="bottom-right"
  data-theme="dark"
></script>

<!-- Spanish UI -->
<script
  src="https://cdn.jsdelivr.net/npm/@pigmilcom/a11y/dist/a11y.cdn.js"
  data-position="bottom-right"
  data-lang="es"
></script>
localStorage.setItem('a11y-lang', 'fr');
window.dispatchEvent(new CustomEvent('pgm-a11y-language-change', {
  detail: { lang: 'fr' }
}));

If you still pass data-lang="fr", that explicit value wins and also updates localStorage['a11y-lang'].

Programmatic control

The CDN build exposes window.PigmilA11y for manual control:

PigmilA11y.mount();    // mount the widget
PigmilA11y.unmount();  // remove the widget and clean up

npm Installation

npm install @pigmilcom/a11y
# yarn
yarn add @pigmilcom/a11y
# pnpm
pnpm add @pigmilcom/a11y

Features

  • Text size — Normal / Large / X-Large
  • High contrast
  • Invert colours
  • Grayscale
  • Reduce motion
  • Highlight links
  • Text spacing (WCAG 1.4.12)
  • Dyslexia-friendly font
  • Persists in localStorage
  • Full keyboard & screen-reader support (role="dialog", aria-checked, aria-expanded)
  • Zero runtime dependencies (React peer dep only)

Dist files

Every build outputs these files to dist/:

File Format Description
index.js CJS npm (unminified, for bundlers)
index.mjs ESM npm (unminified, for bundlers)
index.min.js CJS npm (minified)
index.min.mjs ESM npm (minified)
index.css CSS Stylesheet import (@pigmilcom/a11y/styles)
index.min.css CSS Minified stylesheet
a11y.cdn.js IIFE CDN bundle — React bundled, CSS inlined, minified

Quick start (React)

1 — Import the stylesheet (once, globally)

import '@pigmilcom/a11y/styles';

This single import contains both the panel UI styles and all the accessibility class rules applied to <html>.

2 — Drop in the widget

import a11y from '@pigmilcom/a11y';

// Assign to a capitalized variable to use in JSX
const A11y = a11y;

<A11y className="fixed bottom-4 right-4 rounded" />

The className prop is merged onto the trigger button — use Tailwind classes, custom classes, or anything your bundler supports to position the widget. The lang prop is reactive, and when provided it also syncs localStorage['a11y-lang'].


Customising the widget with CSS

The widget exposes stable a11y-widget-* class names on its key elements as a public API. Target them from a <style> tag (CDN / self-hosted) or your own stylesheet (React):

<style>
  /* Trigger button */
  .a11y-widget-btn {
    border-radius: 8px !important;
    background: rgba(15, 15, 40, 0.9) !important;
  }

  /* Dialog panel */
  .a11y-widget-dialog {
    border-color: rgba(99, 102, 241, 0.4) !important;
  }

  /* Toggle option rows */
  .a11y-widget-toggle-btn:hover {
    background: rgba(99, 102, 241, 0.06) !important;
  }
</style>
Public class Element
a11y-widget-btn Trigger button
a11y-widget-dialog Dialog panel
a11y-widget-toggle-btn Each toggle option

Place your <style> tag after the widget <script> tag so it takes precedence in the cascade. Use !important where the widget's base styles have higher specificity.


Tailwind CSS support

Tailwind utility classes work transparently via the className prop:

import a11y from '@pigmilcom/a11y';
const A11y = a11y;

// Tailwind classes are passed straight through to the trigger button
<A11y className="fixed bottom-6 right-6 rounded-full shadow-xl" lang="de" />

Because the classes come from your source files, Tailwind's JIT scanner picks them up automatically. No purge exceptions or safelist entries needed.


Framework examples

Next.js App Router

// app/layout.jsx
import '@pigmilcom/a11y/styles';
import a11y from '@pigmilcom/a11y';

const A11y = a11y;

export default function RootLayout({ children }) {
    return (
        <html lang="en">
            <body>
                {children}
                <A11y className="fixed bottom-4 right-4 rounded" lang="en" />
            </body>
        </html>
    );
}

The component is already marked 'use client' — no extra wrapper needed.

Vite + React

// src/App.jsx
import a11y from '@pigmilcom/a11y';

const A11y = a11y;

export default function App() {
    return (
        <>
            {/* …your content… */}
            <A11y className="fixed bottom-4 right-4 rounded" lang="pt" />
        </>
    );
}

Props

Prop Type Default Description
className string Extra classes added to the trigger <button>
theme string inferred Widget colour theme: 'auto' | 'light' | 'dark'
lang string localStorage['a11y-lang'] or 'en' Widget UI language: 'en', 'es', 'fr', 'de', 'pt', 'zh', 'ar', 'hi'

theme prop

Value Behaviour
omitted / 'auto' Matches <html class="dark"> or color-scheme: dark; otherwise light
'light' Always renders the light theme
'dark' Always renders the dark theme
import a11y from '@pigmilcom/a11y';
const A11y = a11y;

// Follow the page's html theme (default)
<A11y className="fixed bottom-4 right-4" />

// Equivalent explicit auto mode
<A11y className="fixed bottom-4 right-4" theme="auto" />

// Always light
<A11y className="fixed bottom-4 right-4" theme="light" />

// Always dark
<A11y className="fixed bottom-4 right-4" theme="dark" />

// Change the widget UI language
<A11y className="fixed bottom-4 right-4" lang="zh" />
localStorage.setItem('a11y-lang', 'ar');
window.dispatchEvent(new CustomEvent('pgm-a11y-language-change', {
  detail: { lang: 'ar' }
}));

CSS classes applied to <html>

When a preference is enabled the widget adds a class to document.documentElement. All rules live in @pigmilcom/a11y/styles and can be freely overridden in your own stylesheet.

Class Feature
a11y-text-lg Font size +18 %
a11y-text-xl Font size +45 %
a11y-high-contrast Contrast filter (1.6×)
a11y-invert Invert colours (re-inverts images/video)
a11y-grayscale Grayscale filter
a11y-reduce-motion Strips all animations & transitions
a11y-highlight-links Outlines every link and [role="link"]
a11y-text-spacing Letter / word / line spacing (WCAG 1.4.12)
a11y-dyslexia Switches to a high-readability system font

Storage

Preferences are saved under the localStorage key pgm-a11y as a JSON object. The widget reads and re-applies them on first client render, so preferences survive page reloads and navigation. On SSR the widget hydrates without errors — all DOM access is guarded by a mounted flag.

Widget language is stored separately under localStorage['a11y-lang'].

  • If data-lang or lang is provided, that value is normalized and saved to a11y-lang.
  • If no explicit language is provided, the widget reads a11y-lang.
  • If a11y-lang is missing, the widget sets it to 'en' automatically.
  • Updating a11y-lang and dispatching pgm-a11y-language-change updates the widget language dynamically on the same page.

Requirements

CDN

No dependencies. Works in any HTML page.

npm package

Peer dependency Version
react ≥ 17
react-dom ≥ 17

License

MIT © pigmilcom

Free Usage

The free version is available for any domain and includes:

  • Up to 1,000 requests / day per domain
  • Up to 30,000 requests / month per domain

Full version (white-label)

The full version removes all limits and PIGMIL branding and can be fully white-labeled for your product.

For inquiries contact PIGMIL:

About

Simple, lightweight accessibility widget that enhances usability and adds WCAG 2.1 features to any website instantly. Zero dependencies

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors