ape-accessibility
v0.10.0
Published
Plug-and-play accessibility widget for any web application
Downloads
2,070
Readme
ape-accessibility
Plug-and-play accessibility widget for any web application. Works with React, Next.js, Vue, Nuxt, Angular, vanilla JS — zero configuration required.
The widget renders inside a Shadow DOM, so its styles are fully isolated and will never interfere with your application's CSS.
Installation
npm install ape-accessibility
# or
pnpm add ape-accessibility
# or
yarn add ape-accessibilityUsage
Auto-mount (zero config)
import 'ape-accessibility/auto'
// Widget appears automatically in the bottom-left cornerThat's it. No CSS imports, no providers, no wrappers.
With configuration
import { accessibility } from 'ape-accessibility'
const widget = accessibility.init({
position: 'bottom-right', // 'bottom-left' | 'bottom-right'
zIndex: 9999,
})
accessibility.configure({
theme: {
primary500: '#0ea5e9',
primary600: '#0284c7',
primary700: '#0369a1',
panelBackground: '#f8fafc',
fabActive: '#fde68a',
fabInactive: '#f1f5f9',
backdrop: 'rgba(2, 6, 23, 0.4)',
},
})
// Remove the widget
widget.destroy()React component (recommended)
If you're using React/Next.js, you can mount and configure the widget as a component:
import { AccessibilityWidget } from 'ape-accessibility'
export default function Layout() {
return (
<>
{/* ...your app layout... */}
<AccessibilityWidget
config={{
position: 'bottom-right',
zIndex: 9999,
theme: {
primary500: '#0ea5e9',
primary600: '#0284c7',
primary700: '#0369a1',
panelBackground: '#f8fafc',
fabActive: '#fde68a',
fabInactive: '#f1f5f9',
backdrop: 'rgba(2, 6, 23, 0.4)',
},
}}
/>
</>
)
}Script tag (no bundler)
<script src="https://unpkg.com/ape-accessibility/dist/index.global.js"></script>The widget auto-mounts when the script loads. For manual control:
<script>
const widget = ApeAccessibility.init({ position: 'bottom-right' })
</script>API
| Function | Description |
| -------------------- | ------------------------------------------ |
| accessibility.init(config?) | Mounts the widget. Returns { destroy() } |
| accessibility.destroy() | Removes the widget from the DOM |
| accessibility.configure(config?) | Updates runtime widget config (including theme) |
| accessibility.getConfig() | Returns current widget config |
| accessibility.getSettings() | Returns current accessibility settings |
| accessibility.resetAllSettings() | Resets all settings to their defaults |
Config options
| Option | Type | Default |
| ------------- | ------------------------------------- | --------------- |
| position | 'bottom-left' | 'bottom-right' | 'bottom-left' |
| zIndex | number | 9999 |
| containerId | string | 'ape-accessibility-root' |
| theme | Partial<WidgetTheme> | default theme values |
Theme options
All theme options are optional — pass only what you want to override (Partial<WidgetTheme>).
| Option | Type | Default | Affects |
| ------ | ---- | ------- | ------- |
| primary500 | string | #005dca | Brand color (light) — FAB gradient, active tiles, header, links, focus accents |
| primary600 | string | #004faf | Brand color (mid) — gradient middle stop |
| primary700 | string | #003b8a | Brand color (dark) — gradient end, active text/icons |
| accent | string | #fec905 | Highlight ring on FAB hover/focus |
| panelBackground | string | #f9fafb | Sidebar surface background |
| fabActive | string | #ffd54f | FAB icon color when the menu is open or a feature is active |
| fabInactive | string | #f6f6f6 | FAB icon color at rest |
| backdrop | string | rgba(0, 0, 0, 0.2) | Overlay behind the open panel |
| radiusFab | string | 1.875rem | Corner radius of the FAB + circular buttons |
| radiusPanel | string | 2rem | Corner radius of the slide-in sidebar |
| radiusTile | string | 0.75rem | Corner radius of tiles, the reset button, and sub-panels |
| fontFamily | string | "Work Sans", Inter, system-ui, sans-serif | Font stack for the entire widget |
Note:
primary500/600/700are not three separate roles — they are a 3-stop ramp (light → dark) of a single brand color used for the gradient and accents. Changing one shade keeps the look coherent.
Customization
The widget lives inside a Shadow DOM, so your page's CSS cannot reach into it (that's what keeps it from breaking). There are two supported ways to customize it — both cross the shadow boundary safely.
1. Design tokens (recommended) — coherent theming
Pass a theme to init/configure (or the <AccessibilityWidget config> prop). Tokens are applied as CSS custom properties on the host element and cascade into the Shadow DOM. This is the recommended path: one knob updates every element that uses it, so the design stays coherent.
accessibility.init({
theme: {
primary500: '#9333ea', // the whole widget reskins to purple…
primary600: '#7e22ce', // …FAB, header, active tiles, focus accents, all follow
primary700: '#6b21a8',
radiusTile: '0', // square tiles everywhere at once
fontFamily: '"Inter", system-ui, sans-serif',
},
})See Theme options for the full list.
2. ::part() — fine-grained per-element styling
For control beyond the tokens, the widget exposes its internal elements via ::part(). Target the host container (default id ape-accessibility-root) from your regular page stylesheet:
#ape-accessibility-root::part(fab) {
background-image: none;
background-color: #16a34a;
border-radius: 12px;
}
#ape-accessibility-root::part(panel-header) {
background-image: none;
background-color: #0f766e;
}| Part name | Element |
| ---------------- | ---------------------------------------- |
| fab | Floating trigger button |
| panel | Slide-in sidebar container |
| panel-header | Sidebar header bar |
| reset-button | "Reset settings" button |
| tile | Each feature tile (toggle + cyclic) |
| backdrop | Overlay behind the open panel |
Protected accessibility core
To keep the widget WCAG-compliant no matter how it's themed, a small set of rules cannot be weakened:
- Touch targets stay at a 44×44px minimum (WCAG 2.5.5). You can grow
::part(fab)/::part(tile)etc., but they won't shrink below the floor. - Focus indicators and contrast-critical styles are intentionally not exposed as parts.
Please don't force-override these (e.g. with !important on sizes/outlines) — doing so breaks the accessibility the widget exists to provide.
Features
| Feature | Description | | -------------------- | -------------------------------------------------------- | | Font size | Increase/decrease (90%–120%) | | High contrast | High contrast mode for improved readability | | Saturation | High, low, or monochrome modes | | Dyslexia font | Switches to OpenDyslexic font | | Letter spacing | Adjust letter spacing for better readability | | Line height | Adjust line height / leading | | Highlight headings | Visually highlights all headings on the page | | Highlight links | Visually highlights all links on the page | | Bold text | Applies bold weight to all body text | | Pause animations | Stops all CSS animations and transitions | | Large cursor | Increases cursor size for easier tracking | | Reading guide | Horizontal line that follows the cursor | | Read aloud | Text-to-speech using the Web Speech API | | Page structure | Navigate the page by heading hierarchy | | Hide images | Hides images, videos, and SVGs | | Text alignment | Force left, center, or right alignment | | Accessibility profiles | Presets for visual, cognitive, motor, and senior needs |
How it works
- Widget UI (panel, buttons, animations) renders inside a Shadow DOM, completely isolated from the host page. Your styles won't break, and the widget's styles won't leak.
- Accessibility tools (high contrast, dyslexia font, large cursor, etc.) are injected into the host document intentionally, since they need to affect the entire page.
- React is bundled internally — no peer dependencies, no version conflicts with your app.
Framework compatibility
| Framework | Status | | ---------- | ------ | | React | Works | | Next.js | Works | | Vue | pending | | Nuxt | pending | | Angular | pending | | Vanilla JS | Works | | Any other | pending |
Bundle size
~296 KB minified (~75 KB gzipped). Includes React internally — no external dependencies required.
Development
git clone https://github.com/APE-SENA-2025/ape-accessibility.git
cd ape-accessibility
pnpm install
pnpm devOpens a dev server at http://localhost:3333 with hot reload.
License
All rights reserved.
