npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

a11y-widget-v1

v1.0.0

Published

Accessibility Widget v1 - WCAG 2.1 AA-aligned support layer

Readme

Accessibility Widget v1 — Embed Anywhere

A lightweight, embeddable accessibility widget that provides WCAG 2.1 AA–aligned enhancements for the widget surface + any canonical-rendered content you control, without claiming "full ADA compliance" for the host site.

Overview

This widget is a support layer + render-time accessibility controls — not an overlay that "fixes the whole site." It provides:

  • ✅ Accessibility enhancements for widget UI itself
  • ✅ CSS-based user preference transforms (contrast, text size, spacing)
  • ✅ Keyboard and screen reader support
  • ✅ Global keyboard shortcut (Alt+A) to quickly open widget
  • ✅ Preference persistence (localStorage/cookie)
  • ✅ Optional profile presets (dyslexia-friendly, low-vision, reduced motion)
  • Text-to-Speech: Read selected text or full page aloud with customizable voice settings (including PDF text extraction when available)
  • Translation: Automatically translate page content into multiple languages (translates all text on declared surfaces)
  • Reading Aids: Reading ruler, screen mask, text-only mode, adjustable margins
  • Focus Tools: Customizable cursor size, page magnifier
  • Dictionary: Double-click words to see definitions
  • Inline Tool Management: Use the widget's Tools button to reorder tools and hide/show unused controls
  • Support + Monitoring: Optional backend endpoints for telemetry, install heartbeats, widget errors, support cases, and translation

Scope boundaries: This widget only affects elements you explicitly declare as surfaces. It does not fix host-site HTML outside those surfaces, third-party embeds, or guarantee full-site compliance. PDF text extraction is attempted for same-origin PDFs but may be limited by CORS restrictions.

Quick Start

Installation Options

Choose one of two installation methods:

Option 1: CDN (Recommended for Simple Sites)

Just add this single line to your HTML:

<!-- Use versioned tag to ensure you get the latest stable version -->
<script src="https://cdn.jsdelivr.net/gh/braieswabe/[email protected]/a11y-widget-loader-v1.7.2.js" defer></script>

Note: We use version tags (for example @v1.7.2) instead of branch names (@main) because jsDelivr CDN aggressively caches branch URLs for up to 7 days. Version tags are served immediately and ensure you always get the exact version you specify.

That's it! The widget loads automatically from GitHub. No configuration needed.

Option 2: NPM (Recommended for Bundled Apps)

Install via npm:

npm install @careerdriver/a11y-widget

Then import and initialize in your code:

import { initA11yWidget } from "@careerdriver/a11y-widget";
import "@careerdriver/a11y-widget/styles.css";

initA11yWidget({ 
  siteId: "example.com",
  position: "right"
});

✨ Version Updates:

  • CDN: Update the version tag in your script tag (e.g., @v1.6.10@v1.7.2)
  • NPM: Run npm update @careerdriver/a11y-widget to get the latest version

⌨️ Keyboard Shortcut: Press Alt+A (Option+A on Mac) from anywhere on the page to quickly open/close the accessibility widget. The shortcut doesn't interfere with typing in input fields.

Optional Configuration

CDN Method

If you want to configure surfaces, telemetry, monitoring, or support routing, add configuration before the loader script:

<script>
  window.__A11Y_WIDGET__ = {
    siteId: "example.com",
    apiKey: "YOUR_CLIENT_API_KEY",
    position: "right",  // Optional: "left" or "right"
    keyboardShortcut: "Alt+A",  // Optional: "Alt+A", "Ctrl+Alt+A", or null to disable
    globalMode: false,  // Optional: If true, applies transformations to entire website (fonts, colors, sizes)
    surfaces: ["body", "main"],  // Optional: CSS selectors (ignored if globalMode is true)
    telemetryEndpoint: "https://your-widget-backend.com/api/telemetry"
  };
</script>
<script src="https://cdn.jsdelivr.net/gh/braieswabe/[email protected]/a11y-widget-loader-v1.7.2.js" defer></script>

NPM Method

Pass configuration directly to initA11yWidget():

import { initA11yWidget } from "@careerdriver/a11y-widget";
import "@careerdriver/a11y-widget/styles.css";

initA11yWidget({
  siteId: "example.com",
  apiKey: "YOUR_CLIENT_API_KEY",
  position: "right",
  keyboardShortcut: "Alt+A",
  globalMode: false,
  surfaces: ["body", "main"],
  telemetryEndpoint: "https://your-widget-backend.com/api/telemetry"
});

Global Mode: When enabled, the widget applies transformations (fonts, font sizes, colors, spacing) to the entire website, completely overhauling the user interface. When disabled (default), transformations only apply to declared surfaces.

Tool Management: Visitors can click Tools inside the widget header to show inline up/down and visibility controls beside each tool name. Order and hidden tools persist per visitor.

Monitoring: When telemetryEndpoint is set, the widget also derives /api/widget/heartbeat, /api/widget/errors, /api/support/cases, and /api/translate from the same backend unless you override those endpoints directly.

Authorized Monitoring Installation

The one-line install can run the widget UI without backend monitoring. To use database-backed heartbeat tracking, widget error logging, support cases, or translation, the site must be authorized by the backend first.

  1. Log in to the employee/admin dashboard.
  2. Create or select the client record and copy its API key.
  3. Add every production domain where the widget will run, without protocol, for example example.com and www.example.com.
  4. Use the same siteId in the website snippet that is assigned to that client.
  5. Add the client API key as apiKey or licenseKey in the widget config.
  6. Set telemetryEndpoint to your backend /api/telemetry. The widget will derive heartbeat, error, support, and translation endpoints from the same backend unless they are overridden.

Development origins such as localhost and 127.0.0.1 are allowed for logging endpoints so local demos can submit support cases and heartbeats. Production domains still require a registered domain match or a valid API/license key.

Custom Button Control

To hide the default button and control it with your own header button, see Custom Button Control Guide.

Configuration Options

CDN Method: Configuration is via window.__A11Y_WIDGET__ object or data attributes (set before script loads).

NPM Method: Configuration is passed directly to initA11yWidget(config) function.

Both methods support the same configuration options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | siteId | string | null | Auto-detected from hostname if not provided | | apiKey | string | null | Client API key used by protected backend endpoints | | licenseKey | string | null | Alias for backend authorization when using license-key terminology | | position | "left"\|"right" | "right" | Widget position on screen | | keyboardShortcut | string|null | "Alt+A" | Global keyboard shortcut to open/close widget (e.g., "Alt+A", "Ctrl+Alt+A", or null to disable) | | globalMode | boolean | false | If true, applies transformations to entire website (fonts, colors, sizes). When enabled, surfaces is ignored. | | surfaces | string[] | ["body"] | CSS selectors to mark as data-a11y-surface="true" (ignored if globalMode is true) | | enableTelemetry | boolean | false | Enable telemetry events | | telemetryEndpoint | string | null | Backend endpoint for telemetry (e.g., /api/telemetry) | | heartbeatEndpoint | string | Derived from telemetryEndpoint | Backend endpoint for widget installation heartbeats | | errorEndpoint | string | Derived from telemetryEndpoint | Backend endpoint for widget runtime errors | | supportEndpoint | string | Derived from telemetryEndpoint | Backend endpoint for visitor support cases | | translateEndpoint | string | Derived from telemetryEndpoint | Backend endpoint for server-side translation | | zIndex | number | 2147483000 | Widget z-index | | initialOpen | boolean | false | Open widget on page load | | locale | string | "en" | Locale (future use) | | features | object | See below | Toggle individual features |

Feature Flags

features: {
  contrast: true,        // Contrast modes (default/high/dark/light)
  fontScale: true,       // Text size slider (100-160%)
  spacing: true,         // Text spacing presets (normal/comfortable/max)
  reduceMotion: true,    // Reduce motion toggle
  readableFont: true,    // Readable font toggle
  presets: true,         // Preset buttons (low vision, dyslexia, motion)
  reset: true,           // Reset button
  skipLink: true         // Skip to content link
}

Platform-Specific Installation Guides

How It Works

Surface Scoping vs Global Mode

By Default (Surface Mode): The widget only applies transforms to elements you declare in surfaces. Those elements get data-a11y-surface="true":

<!-- Your HTML -->
<body>
  <main data-canonical-surface="true">
    <p>This content will be transformed</p>
  </main>
  <aside>
    <p>This content will NOT be transformed</p>
  </aside>
</body>
// Widget config
surfaces: ["body", "[data-canonical-surface='true']"]

Global Mode: When globalMode: true is set, the widget applies transformations to the entire website, completely overhauling fonts, font sizes, background colors, and other UI elements. This replaces existing website styles globally:

// Widget config
globalMode: true  // Applies to entire website, not just surfaces

Note: When global mode is enabled, the surfaces configuration is ignored - all elements are transformed.

Preference Persistence

User preferences are stored per domain in:

  1. localStorage (primary)
  2. Cookies (fallback if localStorage unavailable)

Storage key: __a11yWidgetPrefs__

Translation Behavior

When translation is enabled:

  • All text content within declared surfaces ([data-a11y-surface="true"]) is automatically translated
  • Original text is preserved and restored when translation is disabled
  • Language changes trigger automatic re-translation
  • Translations are cached to improve performance
  • Translation API rate limits apply (MyMemory API free tier)

Telemetry (Optional)

If enableTelemetry: true and telemetryEndpoint is set, the widget sends events to your backend:

  • widget_open — Widget panel opened
  • setting_change — User changed a setting
  • reset — User reset preferences
  • widget_close — Widget panel closed

Events include: siteId, event, payload, url, userAgent (no PII).

Protected backend features use the Neon-backed validation tables. A production request to heartbeat, widget errors, support cases, or translation must come from a registered domain or include a valid apiKey/licenseKey. Localhost and 127.0.0.1 are allowed for development logging tests.

API Reference

Telemetry Endpoint

POST /api/telemetry

{
  "siteId": "your-site-id",
  "event": "widget_open",
  "payload": {},
  "url": "https://example.com/page",
  "userAgent": "Mozilla/5.0..."
}

Monitoring Endpoints

These endpoints are derived automatically from telemetryEndpoint unless configured directly:

  • POST /api/widget/heartbeat — Creates or updates the installed-site record with domain, URL, title, favicon, version, browser metadata, and last seen time.
  • POST /api/widget/errors — Stores widget runtime/API failures for Employee Monitoring.
  • POST /api/support/cases — Stores visitor support cases from the widget Support button.
  • POST /api/translate — Runs server-side translation and cache lookup when configured.

Production requests are authorized by allowed domain, client API key, or license key. Make sure NEON_DATABASE_URL is configured on the backend and /api/health reports database: connected.

Config Endpoint (Optional)

GET /api/config/[siteId]

Returns site-specific configuration JSON.

Health Check

GET /api/health

Returns: {"status":"ok","database":"connected"}

See DEPLOYMENT.md for backend setup.

Files

  • a11y-widget.js — Main widget (IIFE, no dependencies)
  • a11y-widget.css — Widget styles + surface transforms
  • support-statement.md — Public support statement (scope boundaries)
  • wcag-matrix.md — WCAG 2.1 AA coverage matrix
  • DEPLOYMENT.md — Deployment guide (Vercel + Neon)

Support Statement

This widget provides accessibility enhancements aligned with WCAG 2.1 AA for supported surfaces only.

What we cover:

  • Widget UI accessibility
  • Declared content surfaces
  • User preference controls

What we don't cover:

  • Host-site HTML outside declared surfaces
  • Third-party embeds (maps, iframes, booking engines)
  • PDFs or downloads
  • Full-site ADA compliance guarantee

See support-statement.md for full details.

WCAG Coverage

For widget UI + declared surfaces, we cover:

  • ✅ 1.4.3 Contrast (Minimum) — Widget UI + contrast modes
  • ✅ 1.4.4 Resize text — Font scaling 100-160%
  • ✅ 1.4.10 Reflow — Responsive at 320px width
  • ✅ 1.4.12 Text spacing — Spacing presets
  • ✅ 2.1.1 Keyboard — Full keyboard operation
  • ✅ 2.4.1 Bypass blocks — Skip link
  • ✅ 2.4.7 Focus visible — Strong focus indicators
  • ✅ 3.2.3 Consistent navigation — Consistent widget UI
  • ✅ 3.3.2 Labels/instructions — All controls labeled
  • ✅ 4.1.2 Name, role, value — Correct ARIA roles/states

See wcag-matrix.md for detailed coverage matrix.

Troubleshooting

Widget Not Appearing

  1. Check browser console for errors
  2. Verify script loads: curl https://yourdomain.com/a11y-widget/v1/a11y-widget.js
  3. Check CSP allows external scripts/styles
  4. Verify surfaces selectors match your HTML

Settings Not Persisting

  1. Check browser localStorage (DevTools → Application → Local Storage)
  2. Verify cookies aren't blocked
  3. Check storage key: __a11yWidgetPrefs__

CSP Issues

If CSP blocks inline scripts, use data attributes:

<script
  src="https://cdn.YOURDOMAIN.com/a11y-widget/v1/a11y-widget.js"
  data-site-id="YOUR_SITE_ID"
  data-position="right"
  defer
></script>

Telemetry Not Sending

  1. Verify enableTelemetry: true
  2. Check telemetryEndpoint is set correctly
  3. Check browser network tab for POST requests
  4. Verify backend endpoint is accessible
  5. Check CORS headers allow your domain

Backend Request Returns 403

  1. Add the deployed domain in the employee/admin dashboard without protocol, for example example.com.
  2. Confirm the snippet uses the assigned siteId.
  3. Include the client apiKey or licenseKey if the domain is not already allowed.
  4. Confirm telemetryEndpoint points to the correct backend /api/telemetry URL.
  5. Confirm /api/health returns database: connected.

Browser Support

  • Chrome/Edge (latest)
  • Firefox (latest)
  • Safari (latest)
  • Mobile browsers (iOS Safari, Chrome Mobile)

Requires: ES5+ JavaScript, CSS Custom Properties (CSS Variables)

License

MIT License — See LICENSE file

Contributing

See docs/DEVELOPER.md for development guidelines.

Deployment

See DEPLOYMENT.md for Vercel + Neon setup instructions.