Get started
Two surfaces, one rule set.
Both packages are live on npm at 0.2.0. The plugin and the CLI run the exact same rule modules — output is identical by construction, and a parity test in the repo asserts it.
The ESLint plugin
A standard flat-config plugin. It also runs under oxlint via jsPlugins, unchanged — the aria repo’s own .oxlintrc.json is a working example.
npm install --save-dev eslint eslint-plugin-aria-a11y// eslint.config.js
import aria from 'eslint-plugin-aria-a11y';
export default [
{ plugins: { 'aria-a11y': aria }, rules: aria.configs.recommended.rules },
];The recommended config sets the three format-tier rules to error — that’s the CI gate — and the five lint-tier rules to warn. Note: installing the package doesn’t wire it in — you have to add it to your eslint.config.js as above, which is a separate step from running the standalone CLI below.
The zero-config CLI
No ESLint config file, no host setup — point it at files or directories and it works, parsing .jsx/.tsx (and plain JS) out of the box.
npx @aria-a11y/cli check [paths] # report a11y diagnostics (both tiers);
# exits nonzero on any format-tier issue — the CI teeth
npx @aria-a11y/cli fix [paths] # apply format-tier (safe, meaning-preserving) fixes onlyUnder the hood the CLI wraps ESLint’s Linter programmatically with a Babel→ESTree parser — so eslint is a real internal dependency. That’s an implementation detail, not something you configure. “Standalone” means no ESLint config and no host — not a claim of zero ESLint code inside.
Optional: declare your design system
Both surfaces pick up an aria.config.{ts,js,json} if present, but require none. Declaring a component’s semantics turns Aria’s guesses into ground truth — diagnostics move from inferred to declared basis, and for a component that renders a non-semantic element, opting in with injectRole graduates a suggestion to a real auto-fix. The line between guess and known moves in your favor as your design system declares more.
// aria.config.ts — optional; how a design system declares component semantics
import { defineConfig } from '@aria/config';
export default defineConfig({
componentSemantics: {
// native <button>: declared so name checks understand it
IconButton: { role: 'button', requiresName: true, nameProp: 'aria-label' },
// <div> that needs a role: opt into injection
MenuButton: { role: 'button', injectRole: true },
},
});Version note
Version note: latest is 0.2.0; anything 0.1.1+ is safe. Avoid only 0.1.0 — it exists in npm’s history but was broken for installers (a packaging bug — its manifest pointed at unshipped src); fixed in 0.1.1 and guarded by a real install-and-import CI check. 0.2.0 makes role injection opt-in (injectRole); details in the repo’s CHANGELOG.