neighbor is an entire ecosystem of accessibility linters and related tools. It provides comprehensive, cross-platform accessibility checks that go far beyond standard tools.
Whether you're writing markup for a web app, styling components with CSS, authoring content, or building native mobile applications, neighbor has you covered. It brings strong, unified accessibility checks to:
- Markup (React, Vue, Angular, Remix, Web Components): By expanding on base tools like
eslint-plugin-jsx-a11y, it finds complex issues like bad ARIA code, incorrect live regions, and missing names. More importantly, it brings these rigorous checks to non-React frameworks where accessibility linting has historically lagged behind. - Styles (CSS): Fills a massive gap in modern CSS accessibility via Stylelint, catching problems like bad CSS that affects zoom, focus, and visual readability.
- Content and prose: Checks documents for exclusionary and ableist language while you type, via a web app, Vale package, or a Microsoft Word add-in.
- Native iOS (WIP): Ships with Native iOS linting using 9 custom SwiftLint rules for SwiftUI accessibility.
- Native Android (WIP): Ships with Native Android linting using 8 custom Android Lint rules for Jetpack Compose.
Additionally, the following tools are currently in the works:
- Browser Extensions: Live page checking via Chrome and Firefox extensions.
- Desktop App: A standalone Electron app for running checks without needing command-line tools.
Note
AI Assisted Development All of the platform adaptations, browser extensions, native plugins, and ecosystem tooling in this repository were largely aided by AI. We could really use the community's help in testing these tools and verifying their real-world usefulness and quality!
Standard tools like axe-core and Lighthouse are essential, but they only test your app after you build it. This makes fixing mistakes slow. neighbor shifts accessibility left, finding mistakes directly in your editor across your entire stack.
- A Comprehensive Suite: It checks for complex problems. Standard tools check simple things like missing
alttext.neighborchecks for harder problems, like missing close buttons on dialogs, broken tab menus, or React Fragments silently droppingaria-*props. - Unified Rules Everywhere: If you switch from React to Vue or Angular, your linter often catches fewer mistakes.
neighborgives you the exact same strict rules for React, Vue, Angular, Remix, Lit Web Components, iOS, and Android. - CSS Accessibility: The only CSS accessibility linter —
stylelint-a11y— has been unmaintained since 2019.neighborprovides 18 modern CSS rules mapped to WCAG Success Criteria, catching problems like hidden focus rings, clipped zoomed text, smooth scrolling without motion fallbacks, andlist-style: nonestripping Safari semantics. - Text and Content Checking: Accessibility is not just code.
neighborflags ableist language, vague calls-to-action, and confusing link text directly in your JS/TS string literals, markdown, or even Microsoft Word. - Native Mobile Integration: Beyond the web, neighbor ships with custom rules for iOS (SwiftUI) and Android (Jetpack Compose).
- Install
- Entry Points
- Setup
- Ecosystem & Integrations
- Peer Dependencies
- Working With Standard Linters
- What Neighbor Adds to the Ecosystem
- Rule Severity
- Roadmap
- Contributing
- See Also
- License
All core neighbor rules are packaged in a single install to make adopting the suite as easy as possible:
npm install --save-dev @a11yfred/neighborThis gives you access to:
- ESLint plugins via different entry points (
/eslint,/eslint-vue,/eslint-angular,/webcomponents) for markup accessibility rules in your framework - Stylelint plugin via the default export or
/stylelintalias for CSS accessibility rules - Content rules via
/contentfor linting of prose in JS/TS/JSX/TSX files
Optional: Vale configuration (for standalone prose/content linting outside of JavaScript):
npm install --save-dev @a11yfred/vale-config-neighbor
vale config pull| Import | Use for |
|---|---|
@a11yfred/neighbor |
Stylelint - CSS rules |
@a11yfred/neighbor/content |
Any JS/TS/JSX/TSX: content and prose rules |
@a11yfred/neighbor/eslint |
React / JSX, Remix 2: markup rules |
@a11yfred/neighbor/eslint-angular |
Angular templates: markup rules |
@a11yfred/neighbor/eslint-vue |
Vue SFCs: markup rules |
@a11yfred/neighbor/lit |
Lit: markup rules |
@a11yfred/neighbor/stylelint |
Stylelint - CSS rules (explicit alias) |
@a11yfred/neighbor/webcomponents |
Web Components / Vanilla HTML: markup rules |
Show setup instructions
If you write plain HTML or Vanilla Web Components (like Lit), you can use the @a11yfred/neighbor/webcomponents configuration. It natively lints standard HTML syntax for accessibility violations!
What you get:
| Plugin | What it checks |
|---|---|
Content linter (@a11yfred/neighbor/content) |
JS strings: ableist language, vague CTAs, unexplained abbreviations, idioms, all-caps prose |
ESLint (@a11yfred/neighbor/webcomponents) |
Markup: Native HTML elements and Lit templates for ARIA misuse, missing labels, etc. |
Stylelint (@a11yfred/neighbor) |
CSS: 18 rules covering focus rings, High Contrast Mode, motion preferences, target size, text spacing, list-style semantics, overflow clipping, font sizing, and more |
Stylelint setup (CSS only, no framework needed):
npm install --save-dev stylelint stylelint-config-standard @a11yfred/neighbor// .stylelintrc.json
{
"extends": ["stylelint-config-standard"],
"plugins": ["@a11yfred/neighbor"],
"rules": {
"neighbor/no-outline-none": true,
"neighbor/no-forced-colors-none": true,
"neighbor/user-preferences": true
}
}Run it:
npx stylelint "**/*.css"Content linter setup (plain JS string literals, no framework needed):
npm install --save-dev eslint @a11yfred/neighbor// eslint.config.js (ESLint flat config, ESLint >= 8)
import neighborContent from '@a11yfred/neighbor/content'
export default [
{
files: ['**/*.js'],
plugins: { ...neighborContent.configs.recommended.plugins },
rules: { ...neighborContent.configs.recommended.rules },
},
]Run it:
npx eslint src/Both together:
// eslint.config.js
import neighborContent from '@a11yfred/neighbor/content'
export default [
{
files: ['**/*.js'],
plugins: { ...neighborContent.configs.recommended.plugins },
rules: { ...neighborContent.configs.recommended.rules },
},
]// .stylelintrc.json
{
"extends": ["stylelint-config-standard"],
"plugins": ["@a11yfred/neighbor"],
"rules": {
"neighbor/no-outline-none": true,
"neighbor/no-forced-colors-none": true,
"neighbor/user-preferences": true
}
}The ESLint markup rules (@a11yfred/neighbor/eslint and variants) require a template syntax to parse (like JSX, Vue templates, or HTML strings). For vanilla HTML or Web Components, you should use the @a11yfred/neighbor/webcomponents plugin along with the @html-eslint/parser!
Show setup instructions
Neighbor works alongside eslint-plugin-jsx-a11y. Install both.
npm install --save-dev eslint-plugin-jsx-a11y @a11yfred/neighbor// eslint.config.js
import neighbor from '@a11yfred/neighbor/eslint'
export default [
{
plugins: { ...neighbor.configs.recommended.plugins },
rules: { ...neighbor.configs.recommended.rules },
},
]Show setup instructions
Remix 2 uses React. Use the React setup. The special Remix rules turn on automatically when you import Remix.
npm install --save-dev eslint-plugin-jsx-a11y @a11yfred/neighbor// eslint.config.js
import neighbor from '@a11yfred/neighbor/eslint'
export default [
{
files: ['**/*.{js,jsx,ts,tsx}'],
plugins: { ...neighbor.configs.recommended.plugins },
rules: { ...neighbor.configs.recommended.rules },
},
]Show setup instructions
Remix 3 works with any framework. Neighbor does not have a special setup for Remix 3. Use the setup for your view framework (like React or Vue).
If you are using React with Remix 3:
npm install --save-dev eslint-plugin-jsx-a11y @a11yfred/neighborimport neighbor from '@a11yfred/neighbor/eslint'
export default [
{
files: ['**/*.{js,jsx,ts,tsx}'],
plugins: { ...neighbor.configs.recommended.plugins },
rules: { ...neighbor.configs.recommended.rules },
},
]If you do not use React with Remix 3, the special Remix rules will not run.
Show setup instructions
npm install --save-dev eslint-plugin-vuejs-accessibility @a11yfred/neighborimport vueParser from 'vue-eslint-parser'
import neighbor from '@a11yfred/neighbor/eslint-vue'
export default [
{
files: ['**/*.vue'],
languageOptions: { parser: vueParser },
plugins: { ...neighbor.configs.recommended.plugins },
rules: { ...neighbor.configs.recommended.rules },
},
]Show setup instructions
npm install --save-dev @angular-eslint/eslint-plugin-template @a11yfred/neighborimport angularTemplateParser from '@angular-eslint/template-parser'
import neighbor from '@a11yfred/neighbor/eslint-angular'
export default [
{
files: ['**/*.html'],
languageOptions: { parser: angularTemplateParser },
plugins: { ...neighbor.configs.recommended.plugins },
rules: { ...neighbor.configs.recommended.rules },
},
{
// Also lint component TypeScript files for the announce() rule
files: ['**/*.ts'],
plugins: { '@a11yfred/neighbor': neighbor },
rules: {
'@a11yfred/neighbor/no-announce-in-render': 'error',
},
},
]Show setup instructions
// .stylelintrc.json
{
"plugins": ["@a11yfred/neighbor"],
"rules": {
"neighbor/user-preferences": true,
"neighbor/no-outline-none": true,
"neighbor/no-forced-colors-none": true
}
}Show setup instructions
The content plugin lints string literals and JSX text in JavaScript, TypeScript, JSX, and TSX files. It is separate from the markup plugins and can be used alongside any of them.
npm install --save-dev @a11yfred/neighbor// eslint.config.js
import neighborContent from '@a11yfred/neighbor/content'
export default [
{
files: ['**/*.{js,jsx,ts,tsx}'],
plugins: { ...neighborContent.configs.recommended.plugins },
rules: { ...neighborContent.configs.recommended.rules },
},
]To use alongside the React markup plugin:
// eslint.config.js
import neighbor from '@a11yfred/neighbor/eslint'
import neighborContent from '@a11yfred/neighbor/content'
export default [
{
files: ['**/*.{js,jsx,ts,tsx}'],
plugins: {
...neighbor.configs.recommended.plugins,
...neighborContent.configs.recommended.plugins,
},
rules: {
...neighbor.configs.recommended.rules,
...neighborContent.configs.recommended.rules,
},
},
]neighbor is an expanding ecosystem that extends beyond traditional JavaScript IDE linters into standalone applications and native platform integrations.
- Web App: A web interface for the neighbor ecosystem.
- Native iOS linting: Custom SwiftLint rules for native iOS (SwiftUI) accessibility.
- Native Android linting: Custom Android Lint rules for Jetpack Compose accessibility.
- Microsoft Word Add-in: An Office.js add-in that checks documents for exclusionary language while you type.
- Vale Dictionary: A compiled Vale-compatible dictionary containing our textlint content vocabulary for standalone Markdown checking.
Upcoming:
- Browser Extensions: Chrome and Firefox plugins.
- Desktop App: An Electron app that runs these checks.
| Peer | Required for |
|---|---|
@angular-eslint/eslint-plugin-template >= 17 |
Angular config |
eslint >= 8 |
Any ESLint entry point |
eslint-plugin-jsx-a11y >= 6 |
React config - neighbor extends it, not replaces it |
eslint-plugin-vuejs-accessibility >= 2 |
Vue config |
stylelint >= 14 |
Stylelint config |
All peers are optional. Install only what your project uses.
The JavaScript ecosystem already has great tools (eslint-plugin-jsx-a11y for React, eslint-plugin-vuejs-accessibility for Vue, @angular-eslint for Angular, and eslint-plugin-lit-a11y for Lit).
As part of providing a cohesive ecosystem, neighbor automatically integrates with them. It detects if you have the standard linter installed for your framework. If you do, it will disable any of its own redundant checks and only run the rules that the standard linter misses, ensuring you get maximum coverage without duplicate warnings. For a full list of omitted redundant rules, see the Framework Omissions section.
neighbor elevates your existing tools by bringing advanced checks and unifying your accessibility linting strategy across every domain.
| Framework / Domain | Ecosystem Integration | neighbor Enhanced Coverage (Rules not in standard tools) |
|---|---|---|
| @ulam | N/A (Internal framework) | 3 specific rules (Checks for announce() abuse in render loops and router collisions) |
| Android (Compose) | Android Lint (built-in) | 8 custom UAST rules (Checks specifically for Modifier chain accessibility, pointerInput semantics, and TalkBack traversal groups) |
| Angular | @angular-eslint/eslint-plugin-template |
~52 rules (30 core rules + 20 portability rules missing from Angular standard + 2 Angular-specific rules like host tabindex) |
| Lit / Web Components | eslint-plugin-lit-a11y |
~51 rules (30 core rules + 20 portability rules + 1 Lit-specific autofocus rule) |
| React / JSX | eslint-plugin-jsx-a11y |
~32 rules (30 core rules + 2 React-specific rules like <Fragment> ARIA drops and SPA focus) |
| Remix | eslint-plugin-jsx-a11y |
~31 rules (30 core rules + Remix missing meta title) |
| Vanilla HTML | @html-eslint/eslint-plugin |
~50 rules (30 core rules + 20 portability rules applied directly to .html AST) |
| Vue | eslint-plugin-vuejs-accessibility |
~53 rules (30 core rules + 20 portability rules missing from Vue standard + 3 Vue-specific rules like <Transition> live regions) |
| CSS (Stylelint) | None maintained | 18 rules (Focus rings, motion preferences, text spacing, target size, overflow clipping, list semantics, font sizing, and more — filling the gap left by the unmaintained stylelint-a11y) |
| Severity | Meaning |
|---|---|
error |
This breaks screen readers or violates HTML rules. You must fix it. |
warn |
This is usually bad, but sometimes you have a good reason to do it. |
off |
This rule is turned off because it gives too many warnings. You can turn it on if you want. |
Yes! You have full control over the rules. If you want to change a rule to a warning, turn off a noisy rule, or enable a rule that is off by default, you can do so in your ESLint or Stylelint configuration:
ESLint (eslint.config.js)
export default [
// ... other config
{
rules: {
// Turn a rule off completely
'@a11yfred/neighbor/no-positive-tabindex': 'off',
// Change an error to a warning
'@a11yfred/neighbor/no-aria-label-on-generic': 'warn',
// Turn on a rule that is off by default
'@a11yfred/neighbor/prefer-aria-disabled': 'error',
// Content rules
'@a11yfred/neighbor/content/no-ableist-language': 'error'
}
}
]Stylelint (stylelint.config.js)
export default {
// ... other config
rules: {
// Turn a rule off
'neighbor/no-outline-none': null,
// Change an error to a warning
'neighbor/no-forced-colors-none': [true, { "severity": "warning" }]
}
}Neighbor's exact markup rule sets, including what is checked for each framework, which rules are errors vs warnings, and how they map to WCAG Success Criteria, are documented in our dedicated rule page.
See Markup Rules for ESLint rules covering React, Remix, Vue, Angular, Lit, and Web Components (ARIA, focus, semantic HTML).
CSS accessibility linting has been an unsolved problem in the JavaScript ecosystem. The only dedicated tool — stylelint-a11y — went unmaintained in 2019 and no successor emerged. Neighbor fills this gap in the ecosystem with 18 rules built from scratch for modern Stylelint (v14+), each mapped to a specific WCAG Success Criterion. It covers focus rings, High Contrast Mode, motion preferences, target size, text spacing, overflow clipping, list semantics, font sizing, screen-reader visibility, and more.
See CSS Rules for the full rule reference, WCAG mappings, and migration notes for stylelint-a11y users.
Neighbor's exact content rule sets, including which rules are errors vs warnings and how they map to WCAG Success Criteria, are documented in our dedicated rule page.
See Content Rules for Textlint rules flagging ableist language, confusing CTAs, jargon, and inclusion problems in web and app copy (works on string literals and JSX text in JS/TS/JSX/TSX files).
Future plans for the neighbor ecosystem:
- Browser extensions: Chrome and Firefox plugins to check pages live.
- Desktop app (Electron): A desktop app that runs these checks.
[x]iOS app: Accessibility checking for iOS apps (SwiftUI).[x]Android app: Accessibility checking for Android apps (Compose).[x]Microsoft Word add-in: Check documents while you type in Word.
- More editor plugins (VS Code, Sublime Text, Xcode, Android Studio, etc.).
- RULES.md - rule index across all domains
- RULES-MARKUP.md - full ESLint rule reference (markup)
- RULES-CSS.md - full Stylelint rule reference (CSS)
- RULES-CONTENT.md - full content rule reference with sources
- iOS Rules - custom SwiftLint rules for native iOS accessibility
- Android Rules - custom Android Lint rules for Jetpack Compose
@a11yfred/vale-config-neighbor- companion Vale package for prose linting in Markdown, MDX, and HTML. Seepackages/vale-config-neighborin this monorepo.
MIT