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

aria-ease

v2.8.4

Published

Out-of-the-box accessibility utility package to develop production ready applications.

Readme

Aria-Ease

Out of the box accessibility utility package to develop production ready applications.

npm version License: ISC Bundle Size npm downloads

✨ Features

  • 🎯 Tree-shakable - Import only what you need (1.4KB - 3.7KB per component)
  • WCAG Compliant - Follows WAI-ARIA best practices
  • ⌨️ Keyboard Navigation - Full keyboard support out of the box
  • 🧪 Contract Testing - Built-in accessibility testing framework
  • 🎭 Framework Agnostic - Works with React, Vue, vanilla JS, etc.
  • 🔍 CLI Audit Tool - Automated accessibility testing for your sites
  • 📦 TypeScript Support - Full type definitions included

📦 Installation

npm i aria-ease
# or
yarn add aria-ease
# or
pnpm add aria-ease

🚀 Quick Start

Automated Accessibility Audits (CLI)

Run automated accessibility audits on your website with one command:

npx aria-ease audit --url https://yoursite.com

This generates comprehensive reports in JSON, CSV, and HTML formats showing all accessibility violations detected by axe-core.

Create a config file for multiple pages and custom settings:

// ariaease.config.js (or .mjs, .cjs, .json, .ts)
export default {
  audit: {
    urls: [
      "https://yoursite.com",
      "https://yoursite.com/about",
      "https://yoursite.com/contact",
    ],
    output: {
      format: "html", // 'json' | 'csv' | 'html' | 'all'
      out: "./accessibility-reports",
    },
  },
};

Then run:

npx aria-ease audit

Supported config formats:

  • ariaease.config.js (ES modules)
  • ariaease.config.mjs (ES modules explicit)
  • ariaease.config.cjs (CommonJS)
  • ariaease.config.json (JSON)
  • ariaease.config.ts (TypeScript - experimental)

The CLI will automatically find and load your config file, with validation to catch errors early.

Perfect for CI/CD pipelines to catch accessibility issues before production!


📚 Component API

🍔 Menu (Dropdowns)

Creates accessible menus with focus trapping and keyboard navigation. Works for dropdowns that toggles display with interactive items.

Features:

  • Arrow key navigation
  • Escape key closes menu and restores focus
  • Focus trap within menu
  • Submenu support
import * as Menu from "aria-ease/menu";

// React Example
useEffect(() => {
  menuRef.current = Menu.makeMenuAccessible({
    menuId: "menu-div",
    menuItemsClass: "profile-menu-items",
    triggerId: "display-button",
  });

  return () => menuRef.current.cleanup(); // Clean up on unmount
}, []);

// Programmatically control
menuRef.current.openMenu(); // Open the menu
menuRef.current.closeMenu(); // Close the menu
menuRef.current.refresh(); // Refresh the cache after dynamically adding/removing a menu item

// Vanilla JS Example
const menu = Menu.makeMenuAccessible({
  menuId: "dropdown-menu",
  menuItemsClass: "menu-item",
  triggerId: "menu-button",
});

// Programmatically control
menu.openMenu();
menu.closeMenu();

// If you dynamically add/remove menu items, refresh the cache
menu.refresh();

Required HTML structure:

<button
  id="menu-button"
  aria-expanded="false"
  aria-controls="dropdown-menu"
  aria-haspopup="true"
>
  Menu
</button>
<div
  id="dropdown-menu"
  style="display: none;"
  aria-labelledby="menu-button"
  role="menu"
>
  <a role="menuitem" href="#" class="menu-item">Item 1</a>
  <a role="menuitem" href="#" class="menu-item">Item 2</a>
  <button role="menuitem" class="menu-item">Item 3</button>
</div>

🎮 Live Demo


🪗 Accordion

Updates aria-expanded attributes for accordion panels.

import { updateAccordionTriggerAriaAttributes } from "aria-ease/accordion";

const accordionStates = [
  { expanded: true },
  { expanded: false },
  { expanded: false },
];

// Call when accordion state changes
updateAccordionTriggerAriaAttributes(
  "accordion-container", // Container ID
  "accordion-trigger", // Shared class for triggers
  accordionStates, // State array
  0 // Index of trigger that changed
);

HTML structure:

<div id="accordion-container">
  <button
    class="accordion-trigger"
    aria-expanded="false"
    aria-controls="panel-1"
  >
    Section 1
  </button>
  <div id="panel-1">Content 1</div>

  <button
    class="accordion-trigger"
    aria-expanded="false"
    aria-controls="panel-2"
  >
    Section 2
  </button>
  <div id="panel-2">Content 2</div>
</div>

✅ Checkbox

Updates aria-checked attributes for custom checkboxes.

import { updateCheckboxAriaAttributes } from "aria-ease/checkbox";

const checkboxStates = [
  { checked: true },
  { checked: false },
  { checked: true },
];

// Call when checkbox is toggled
function handleCheckboxClick(index) {
  checkboxStates[index].checked = !checkboxStates[index].checked;

  updateCheckboxAriaAttributes(
    "checkbox-group",
    "custom-checkbox",
    checkboxStates,
    index
  );
}

HTML structure:

<div id="checkbox-group">
  <div
    class="custom-checkbox"
    role="checkbox"
    aria-checked="false"
    aria-label="Option 1"
  ></div>
  <div
    class="custom-checkbox"
    role="checkbox"
    aria-checked="false"
    aria-label="Option 2"
  ></div>
</div>

🔘 Radio Button

Updates aria-checked attributes for custom radio buttons.

import { updateRadioAriaAttributes } from "aria-ease/radio";

const radioStates = [{ checked: true }, { checked: false }, { checked: false }];

function handleRadioSelect(index) {
  // Uncheck all, check selected
  radioStates.forEach((state, i) => {
    state.checked = i === index;
  });

  updateRadioAriaAttributes("radio-group", "custom-radio", radioStates);
}

🔀 Toggle Button

Updates aria-pressed attributes for toggle buttons.

import { updateToggleAriaAttribute } from "aria-ease/toggle";

const toggleStates = [{ pressed: false }, { pressed: true }];

function handleToggle(index) {
  toggleStates[index].pressed = !toggleStates[index].pressed;

  updateToggleAriaAttribute("toggle-container", "toggle-btn", toggleStates);
}

🧱 Block (Generic Focusable Groups)

Makes groups of elements keyboard navigable with arrow keys. Perfect for custom controls, toolbars, or any grouped interactive elements.

import { makeBlockAccessible } from "aria-ease/block";

const blockInstance = makeBlockAccessible({
  blockId: "toolbar",
  blockItemsClass: "tool-button",
});

// Clean up when done
blockInstance.current.cleanup();

🧪 Testing Your Components

Aria-Ease includes a built-in testing framework for automated accessibility validation:

import { testUiComponent } from "aria-ease/test";

// In your test file (Vitest, Jest, etc.)
test("menu is accessible", async () => {
  const { container } = render(<MyMenu />);

  // Runs axe-core + contract tests
  const result = await testUiComponent(
    "menu",
    container,
    "http://localhost:3000" // Optional: full E2E with Playwright
  );

  expect(result.violations).toHaveLength(0);
});

📦 Bundle Size

Aria-Ease is designed to be lightweight and tree-shakable:

| Import | Size (ESM) | | ---------------------------- | --------------------- | | aria-ease/accordion | ~1.5KB | | aria-ease/checkbox | ~1.6KB | | aria-ease/radio | ~1.6KB | | aria-ease/toggle | ~1.4KB | | aria-ease/menu | ~3.7KB | | aria-ease/block | ~1.7KB | | Full bundle (all components) | ~416KB (uncompressed) |

💡 Tip: Always import individual components for optimal bundle size:

// ✅ Good - only imports menu code (~3.7KB)
import { makeMenuAccessible } from "aria-ease/menu";
//or
import * as Block from "aria-ease/block";

// ❌ Avoid - imports everything (~416KB)
import { makeMenuAccessible } from "aria-ease";

⚠️ Important: React StrictMode

If using React StrictMode, be aware it intentionally calls effects twice in development. This can cause issues with imperative DOM manipulation. Either:

  1. Remove <React.StrictMode> in development, or
  2. Use proper cleanup functions:
useEffect(() => {
  menuRef.current = Menu.makeMenuAccessible({...});
  return () => menuRef.current.cleanup(); // Prevents double-initialization
}, []);

🎨 Focus Styling

Aria-Ease handles ARIA attributes and keyboard navigation, but you must provide visible focus styles:

:focus {
  outline: 2px solid rgba(0, 91, 211, 1);
  outline-offset: 2px;
}

/* Or custom styles */
.menu-item:focus {
  background: #e3f2fd;
  box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.3);
}

Without visible focus indicators, keyboard users cannot tell which element is active.


🌐 Browser Support

Aria-Ease supports all modern browsers:

| Browser | Minimum Version | | ------- | --------------- | | Chrome | Last 2 versions | | Firefox | Last 2 versions | | Safari | Last 2 versions | | Edge | Last 2 versions |

Not supported: Internet Explorer 11 and below

Requirements:

  • ES6+ support
  • querySelector and querySelectorAll
  • addEventListener and removeEventListener
  • Modern event handling (KeyboardEvent, FocusEvent)

For older browser support, use a polyfill service or transpile with appropriate targets.


📖 More Resources


🤝 Contributing

We welcome contributions! See our contribution guidelines to get started.


📄 License

ISC License - see LICENSE file for details.


Created by Isaac Victor