eslint-plugin-react-a11y 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +110 -0
- package/CHANGELOG.md +37 -0
- package/LICENSE +22 -0
- package/README.md +213 -0
- package/package.json +79 -0
- package/src/index.d.ts +40 -0
- package/src/index.js +279 -0
- package/src/rules/alt-text.d.ts +23 -0
- package/src/rules/alt-text.js +205 -0
- package/src/rules/anchor-ambiguous-text.d.ts +20 -0
- package/src/rules/anchor-ambiguous-text.js +169 -0
- package/src/rules/anchor-has-content.d.ts +20 -0
- package/src/rules/anchor-has-content.js +85 -0
- package/src/rules/anchor-is-valid.d.ts +23 -0
- package/src/rules/anchor-is-valid.js +100 -0
- package/src/rules/aria-activedescendant-has-tabindex.d.ts +15 -0
- package/src/rules/aria-activedescendant-has-tabindex.js +63 -0
- package/src/rules/aria-props.d.ts +15 -0
- package/src/rules/aria-props.js +51 -0
- package/src/rules/aria-role.d.ts +21 -0
- package/src/rules/aria-role.js +72 -0
- package/src/rules/aria-unsupported-elements.d.ts +15 -0
- package/src/rules/aria-unsupported-elements.js +54 -0
- package/src/rules/autocomplete-valid.d.ts +20 -0
- package/src/rules/autocomplete-valid.js +79 -0
- package/src/rules/click-events-have-key-events.d.ts +15 -0
- package/src/rules/click-events-have-key-events.js +60 -0
- package/src/rules/control-has-associated-label.d.ts +24 -0
- package/src/rules/control-has-associated-label.js +178 -0
- package/src/rules/heading-has-content.d.ts +20 -0
- package/src/rules/heading-has-content.js +72 -0
- package/src/rules/html-has-lang.d.ts +15 -0
- package/src/rules/html-has-lang.js +50 -0
- package/src/rules/iframe-has-title.d.ts +15 -0
- package/src/rules/iframe-has-title.js +51 -0
- package/src/rules/img-redundant-alt.d.ts +21 -0
- package/src/rules/img-redundant-alt.js +85 -0
- package/src/rules/interactive-supports-focus.d.ts +20 -0
- package/src/rules/interactive-supports-focus.js +81 -0
- package/src/rules/label-has-associated-control.d.ts +24 -0
- package/src/rules/label-has-associated-control.js +93 -0
- package/src/rules/lang.d.ts +15 -0
- package/src/rules/lang.js +53 -0
- package/src/rules/media-has-caption.d.ts +22 -0
- package/src/rules/media-has-caption.js +84 -0
- package/src/rules/mouse-events-have-key-events.d.ts +17 -0
- package/src/rules/mouse-events-have-key-events.js +62 -0
- package/src/rules/no-access-key.d.ts +15 -0
- package/src/rules/no-access-key.js +43 -0
- package/src/rules/no-aria-hidden-on-focusable.d.ts +15 -0
- package/src/rules/no-aria-hidden-on-focusable.js +67 -0
- package/src/rules/no-autofocus.d.ts +20 -0
- package/src/rules/no-autofocus.js +59 -0
- package/src/rules/no-distracting-elements.d.ts +20 -0
- package/src/rules/no-distracting-elements.js +64 -0
- package/src/rules/no-interactive-element-to-noninteractive-role.d.ts +18 -0
- package/src/rules/no-interactive-element-to-noninteractive-role.js +86 -0
- package/src/rules/no-keyboard-inaccessible-elements.d.ts +24 -0
- package/src/rules/no-keyboard-inaccessible-elements.js +136 -0
- package/src/rules/no-missing-aria-labels.d.ts +24 -0
- package/src/rules/no-missing-aria-labels.js +131 -0
- package/src/rules/no-noninteractive-element-interactions.d.ts +20 -0
- package/src/rules/no-noninteractive-element-interactions.js +78 -0
- package/src/rules/no-noninteractive-element-to-interactive-role.d.ts +18 -0
- package/src/rules/no-noninteractive-element-to-interactive-role.js +95 -0
- package/src/rules/no-noninteractive-tabindex.d.ts +22 -0
- package/src/rules/no-noninteractive-tabindex.js +172 -0
- package/src/rules/no-redundant-roles.d.ts +24 -0
- package/src/rules/no-redundant-roles.js +115 -0
- package/src/rules/no-static-element-interactions.d.ts +20 -0
- package/src/rules/no-static-element-interactions.js +72 -0
- package/src/rules/prefer-tag-over-role.d.ts +15 -0
- package/src/rules/prefer-tag-over-role.js +101 -0
- package/src/rules/role-has-required-aria-props.d.ts +15 -0
- package/src/rules/role-has-required-aria-props.js +65 -0
- package/src/rules/role-supports-aria-props.d.ts +15 -0
- package/src/rules/role-supports-aria-props.js +115 -0
- package/src/rules/scope.d.ts +15 -0
- package/src/rules/scope.js +49 -0
- package/src/rules/tabindex-no-positive.d.ts +15 -0
- package/src/rules/tabindex-no-positive.js +55 -0
- package/src/types/index.d.ts +208 -0
- package/src/types/index.js +7 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
> Context for AI coding agents working on eslint-plugin-react-a11y
|
|
4
|
+
|
|
5
|
+
## Setup Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies (from monorepo root)
|
|
9
|
+
npm install
|
|
10
|
+
|
|
11
|
+
# Build this package
|
|
12
|
+
nx build eslint-plugin-react-a11y
|
|
13
|
+
|
|
14
|
+
# Run tests
|
|
15
|
+
nx test eslint-plugin-react-a11y
|
|
16
|
+
|
|
17
|
+
# Run tests with coverage
|
|
18
|
+
nx test eslint-plugin-react-a11y --coverage
|
|
19
|
+
|
|
20
|
+
# Lint this package
|
|
21
|
+
nx lint eslint-plugin-react-a11y
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Code Style
|
|
25
|
+
|
|
26
|
+
- TypeScript strict mode with `@interlace/eslint-devkit` types
|
|
27
|
+
- Use `AST_NODE_TYPES` constants, never string literals for node types
|
|
28
|
+
- Use `formatLLMMessage()` for all rule error messages
|
|
29
|
+
- Include WCAG reference in every accessibility message
|
|
30
|
+
- Use `c8 ignore` comments with documented reasons for untestable code
|
|
31
|
+
- Single-pass AST traversal patterns (O(n) complexity)
|
|
32
|
+
|
|
33
|
+
## Testing Instructions
|
|
34
|
+
|
|
35
|
+
- Tests use `@typescript-eslint/rule-tester` with Vitest
|
|
36
|
+
- Each rule has `index.ts` (implementation) and `*.test.ts` (tests) in same directory
|
|
37
|
+
- Run specific rule test: `nx test eslint-plugin-react-a11y --testPathPattern="img-requires-alt"`
|
|
38
|
+
- Coverage target: ≥90% lines, ≥95% functions
|
|
39
|
+
- All tests must pass before committing
|
|
40
|
+
|
|
41
|
+
## Project Structure
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
src/
|
|
45
|
+
├── index.ts # Plugin entry, 4 configs
|
|
46
|
+
└── rules/ # 37 rule directories
|
|
47
|
+
└── [rule-name]/
|
|
48
|
+
├── index.ts # Rule implementation
|
|
49
|
+
└── *.test.ts # Rule tests
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Plugin Purpose
|
|
53
|
+
|
|
54
|
+
React accessibility ESLint plugin with **37 LLM-optimized rules** for WCAG 2.1 compliance. Covers anchor elements, ARIA attributes, form controls, images, interactive elements, and focus management.
|
|
55
|
+
|
|
56
|
+
## Available Presets
|
|
57
|
+
|
|
58
|
+
| Preset | Description |
|
|
59
|
+
| ------------- | --------------------------------------- |
|
|
60
|
+
| `recommended` | Balanced accessibility (37 rules mixed) |
|
|
61
|
+
| `strict` | All 37 rules as errors |
|
|
62
|
+
| `wcag-a` | WCAG 2.1 Level A compliance (16 rules) |
|
|
63
|
+
| `wcag-aa` | WCAG 2.1 Level AA compliance (24 rules) |
|
|
64
|
+
|
|
65
|
+
## Rule Categories
|
|
66
|
+
|
|
67
|
+
| Category | Rules | WCAG |
|
|
68
|
+
| -------- | -------------------------------------------------------------------------------------------- | ------------ |
|
|
69
|
+
| Anchor | `anchor-ambiguous-text`, `anchor-has-content`, `anchor-is-valid` | 2.4.4 |
|
|
70
|
+
| ARIA | `aria-activedescendant-has-tabindex`, `aria-props`, `aria-role`, `aria-unsupported-elements` | 4.1.2 |
|
|
71
|
+
| Forms | `autocomplete-valid`, `control-has-associated-label`, `label-has-associated-control` | 1.3.1, 1.3.5 |
|
|
72
|
+
| Events | `click-events-have-key-events`, `mouse-events-have-key-events` | 2.1.1 |
|
|
73
|
+
| Images | `img-redundant-alt`, `img-requires-alt` | 1.1.1 |
|
|
74
|
+
| Focus | `interactive-supports-focus`, `no-autofocus`, `tabindex-no-positive` | 2.4.3 |
|
|
75
|
+
|
|
76
|
+
## Error Message Format
|
|
77
|
+
|
|
78
|
+
All rules produce WCAG-referenced messages:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
♿ WCAG 1.1.1 | Image missing alt text | CRITICAL
|
|
82
|
+
Fix: Add alt="Descriptive text about image" | https://www.w3.org/WAI/tutorials/images/
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Common Fix Patterns
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
// Image alt (WCAG 1.1.1)
|
|
89
|
+
// BAD: <img src="photo.jpg" />
|
|
90
|
+
// GOOD: <img src="photo.jpg" alt="Description of image" />
|
|
91
|
+
|
|
92
|
+
// Anchor content (WCAG 2.4.4)
|
|
93
|
+
// BAD: <a href="/page">Click here</a>
|
|
94
|
+
// GOOD: <a href="/page">View product details</a>
|
|
95
|
+
|
|
96
|
+
// Form labels (WCAG 1.3.1)
|
|
97
|
+
// BAD: <input type="text" />
|
|
98
|
+
// GOOD: <label>Name: <input type="text" /></label>
|
|
99
|
+
// GOOD: <input type="text" aria-label="Name" />
|
|
100
|
+
|
|
101
|
+
// Keyboard events (WCAG 2.1.1)
|
|
102
|
+
// BAD: <div onClick={handleClick}>...</div>
|
|
103
|
+
// GOOD: <div onClick={handleClick} onKeyDown={handleKeyDown} tabIndex={0}>...</div>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Security Considerations
|
|
107
|
+
|
|
108
|
+
- All rules map to WCAG 2.1 success criteria
|
|
109
|
+
- Covers Level A, AA, and AAA requirements
|
|
110
|
+
- Prevents common accessibility anti-patterns
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2025-12-05
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial release with 37 accessibility rules
|
|
13
|
+
- WCAG 2.1 Level A, AA, and AAA coverage
|
|
14
|
+
- LLM-optimized error messages with structured 2-line format
|
|
15
|
+
- Auto-fix capabilities for applicable rules
|
|
16
|
+
- ESLint 8 and ESLint 9 flat config support
|
|
17
|
+
- TypeScript type definitions for all rule options
|
|
18
|
+
- Four preset configurations:
|
|
19
|
+
- `recommended` - Balanced accessibility enforcement
|
|
20
|
+
- `strict` - All rules as errors
|
|
21
|
+
- `wcag-a` - WCAG 2.1 Level A compliance
|
|
22
|
+
- `wcag-aa` - WCAG 2.1 Level AA compliance
|
|
23
|
+
|
|
24
|
+
### Rule Categories
|
|
25
|
+
|
|
26
|
+
- **Anchor Rules (3)**: `anchor-ambiguous-text`, `anchor-has-content`, `anchor-is-valid`
|
|
27
|
+
- **ARIA Rules (4)**: `aria-activedescendant-has-tabindex`, `aria-props`, `aria-role`, `aria-unsupported-elements`
|
|
28
|
+
- **Form & Input Rules (3)**: `autocomplete-valid`, `control-has-associated-label`, `label-has-associated-control`
|
|
29
|
+
- **Event Rules (2)**: `click-events-have-key-events`, `mouse-events-have-key-events`
|
|
30
|
+
- **Content Rules (5)**: `heading-has-content`, `html-has-lang`, `iframe-has-title`, `lang`, `media-has-caption`
|
|
31
|
+
- **Image Rules (2)**: `img-redundant-alt`, `img-requires-alt`
|
|
32
|
+
- **Interactive Element Rules (6)**: `interactive-supports-focus`, `no-interactive-element-to-noninteractive-role`, `no-noninteractive-element-interactions`, `no-noninteractive-element-to-interactive-role`, `no-noninteractive-tabindex`, `no-static-element-interactions`
|
|
33
|
+
- **Focus & Navigation Rules (5)**: `no-access-key`, `no-aria-hidden-on-focusable`, `no-autofocus`, `no-keyboard-inaccessible-elements`, `tabindex-no-positive`
|
|
34
|
+
- **Visual & Distraction Rules (3)**: `no-distracting-elements`, `no-missing-aria-labels`, `no-redundant-roles`
|
|
35
|
+
- **Role Rules (3)**: `role-has-required-aria-props`, `role-supports-aria-props`, `prefer-tag-over-role`
|
|
36
|
+
- **Scope Rule (1)**: `scope`
|
|
37
|
+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ofri Peretz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://eslint.interlace.tools" target="blank"><img src="https://eslint.interlace.tools/eslint-interlace-logo-light.svg" alt="ESLint Interlace Logo" width="120" /></a>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
Accessibility (a11y) rules for React applications, enforcing WCAG standards.
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/eslint-plugin-react-a11y" target="_blank"><img src="https://img.shields.io/npm/v/eslint-plugin-react-a11y.svg" alt="NPM Version" /></a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/eslint-plugin-react-a11y" target="_blank"><img src="https://img.shields.io/npm/dm/eslint-plugin-react-a11y.svg" alt="NPM Downloads" /></a>
|
|
12
|
+
<a href="https://opensource.org/licenses/MIT" target="_blank"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="Package License" /></a>
|
|
13
|
+
<a href="https://app.codecov.io/gh/ofri-peretz/eslint/components?components%5B0%5D=react-a11y" target="_blank"><img src="https://codecov.io/gh/ofri-peretz/eslint/graph/badge.svg?component=react-a11y" alt="Codecov" /></a>
|
|
14
|
+
<a href="https://github.com/ofri-peretz/eslint" target="_blank"><img src="https://img.shields.io/badge/Since-Dec_2025-blue?logo=rocket&logoColor=white" alt="Since Dec 2025" /></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
## Description
|
|
18
|
+
|
|
19
|
+
This plugin ensures your React applications are accessible to all users by strictly enforcing WCAG standards. It automatically detects common accessibility issues in your JSX, such as missing alt text or improper aria labels, and guides you toward compliant solutions. Implementing these rules helps you build inclusive web experiences that meet modern accessibility requirements.
|
|
20
|
+
|
|
21
|
+
## Philosophy
|
|
22
|
+
|
|
23
|
+
**Interlace** fosters **strength through integration**. We **interlace** accessibility directly into your workflow, creating inclusive applications by design. Tools should **guide rather than gatekeep**, providing educational feedback that strengthens developers.
|
|
24
|
+
|
|
25
|
+
**Why an independent ecosystem?** 🚀 Ship fast without upstream bureaucracy • 🤖 AI-optimized messages (WCAG, severity, fixes) • ⚡ Unified codebase for performance • 🏗️ Consistent patterns across all plugins • 📚 Educational "why" explanations
|
|
26
|
+
|
|
27
|
+
All rules are **clean-room implementations** following `eslint-plugin-jsx-a11y` naming conventions — familiar API, better engineering.
|
|
28
|
+
|
|
29
|
+
## Getting Started
|
|
30
|
+
|
|
31
|
+
- To check out the [guide](https://eslint.interlace.tools/docs/react-a11y), visit [eslint.interlace.tools](https://eslint.interlace.tools). 📚
|
|
32
|
+
- 要查看中文 [指南](https://eslint.interlace.tools/docs/react-a11y), 请访问 [eslint.interlace.tools](https://eslint.interlace.tools). 📚
|
|
33
|
+
- [가이드](https://eslint.interlace.tools/docs/react-a11y) 문서는 [eslint.interlace.tools](https://eslint.interlace.tools)에서 확인하실 수 있습니다. 📚
|
|
34
|
+
- [ガイド](https://eslint.interlace.tools/docs/react-a11y)は [eslint.interlace.tools](https://eslint.interlace.tools)でご確認ください。 📚
|
|
35
|
+
- Para ver la [guía](https://eslint.interlace.tools/docs/react-a11y), visita [eslint.interlace.tools](https://eslint.interlace.tools). 📚
|
|
36
|
+
- للاطلاع على [الدليل](https://eslint.interlace.tools/docs/react-a11y)، قم بزيارة [eslint.interlace.tools](https://eslint.interlace.tools). 📚
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install eslint-plugin-react-a11y --save-dev
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick Start
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
// eslint.config.js
|
|
46
|
+
import reactA11y from 'eslint-plugin-react-a11y';
|
|
47
|
+
|
|
48
|
+
export default [reactA11y.configs.recommended];
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## ⚙️ Configuration Presets
|
|
52
|
+
|
|
53
|
+
| Preset | Description |
|
|
54
|
+
| :------------ | :---------------------------------------------------------------------------- |
|
|
55
|
+
| `recommended` | Enables critical accessibility rules (WCAG Level A as errors, AA as warnings) |
|
|
56
|
+
| `strict` | Enforces all rules as errors for maximum WCAG compliance |
|
|
57
|
+
| `wcag-a` | Only rules required for WCAG 2.1 Level A compliance |
|
|
58
|
+
| `wcag-aa` | Includes Level A + additional rules for Level AA compliance |
|
|
59
|
+
|
|
60
|
+
## Configuration Examples
|
|
61
|
+
|
|
62
|
+
### Basic Usage
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
// eslint.config.js
|
|
66
|
+
import reactA11y from 'eslint-plugin-react-a11y';
|
|
67
|
+
|
|
68
|
+
export default [reactA11y.configs.recommended];
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### With TypeScript
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
import reactA11y from 'eslint-plugin-react-a11y';
|
|
75
|
+
import tseslint from 'typescript-eslint';
|
|
76
|
+
|
|
77
|
+
export default [
|
|
78
|
+
...tseslint.configs.recommended,
|
|
79
|
+
reactA11y.configs.recommended,
|
|
80
|
+
{
|
|
81
|
+
files: ['**/*.{ts,tsx}'],
|
|
82
|
+
rules: {
|
|
83
|
+
'react-a11y/img-requires-alt': 'error',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Strict WCAG Compliance
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
import reactA11y from 'eslint-plugin-react-a11y';
|
|
93
|
+
|
|
94
|
+
export default [
|
|
95
|
+
reactA11y.configs['wcag-aa'],
|
|
96
|
+
{
|
|
97
|
+
// Additional customizations
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Custom Configuration
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
import reactA11y from 'eslint-plugin-react-a11y';
|
|
106
|
+
|
|
107
|
+
export default [
|
|
108
|
+
{
|
|
109
|
+
plugins: {
|
|
110
|
+
'react-a11y': reactA11y,
|
|
111
|
+
},
|
|
112
|
+
rules: {
|
|
113
|
+
'react-a11y/img-requires-alt': [
|
|
114
|
+
'error',
|
|
115
|
+
{
|
|
116
|
+
allowAriaLabel: true,
|
|
117
|
+
allowAriaLabelledby: true,
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
'react-a11y/anchor-ambiguous-text': [
|
|
121
|
+
'warn',
|
|
122
|
+
{
|
|
123
|
+
words: ['click here', 'here', 'more', 'read more', 'learn more'],
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Rules
|
|
132
|
+
|
|
133
|
+
**Legend**
|
|
134
|
+
|
|
135
|
+
| Icon | Description |
|
|
136
|
+
| :--: | :----------------------------------------------------------------- |
|
|
137
|
+
| 💼 | **Recommended**: Included in the recommended preset. |
|
|
138
|
+
| ⚠️ | **Warns**: Set towarn in recommended preset. |
|
|
139
|
+
| 🔧 | **Auto-fixable**: Automatically fixable by the `--fix` CLI option. |
|
|
140
|
+
| 💡 | **Suggestions**: Providing code suggestions in IDE. |
|
|
141
|
+
| 🚫 | **Deprecated**: This rule is deprecated. |
|
|
142
|
+
|
|
143
|
+
| Rule | WCAG Criterion | Description | 💼 | ⚠️ | 🔧 | 💡 | 🚫 |
|
|
144
|
+
| :------------------------------------------------------------------------------------------------------------------ | :------------- | :---------------------------------------------------- | :-: | :-: | :-: | :-: | :-: |
|
|
145
|
+
| [`alt-text`](https://eslint.interlace.tools/docs/react-a11y/rules/alt-text) | 1.1.1 | Image missing alt text | 💼 | | | | |
|
|
146
|
+
| [`html-has-lang`](https://eslint.interlace.tools/docs/react-a11y/rules/html-has-lang) | 3.1.1 | html element missing lang attribute | 💼 | | | | |
|
|
147
|
+
| [`iframe-has-title`](https://eslint.interlace.tools/docs/react-a11y/rules/iframe-has-title) | 2.4.1 | iframe element missing title | 💼 | | | | |
|
|
148
|
+
| [`mouse-events-have-key-events`](https://eslint.interlace.tools/docs/react-a11y/rules/mouse-events-have-key-events) | 2.1.1 | onMouseOver must be accompanied by onFocus | 💼 | | | | |
|
|
149
|
+
| [`no-access-key`](https://eslint.interlace.tools/docs/react-a11y/rules/no-access-key) | 2.1.1 | No access key attribute allowed | 💼 | | | | |
|
|
150
|
+
| [`no-autofocus`](https://eslint.interlace.tools/docs/react-a11y/rules/no-autofocus) | 2.4.3 | No autofocus attribute allowed | 💼 | | | | |
|
|
151
|
+
| [`no-distracting-elements`](https://eslint.interlace.tools/docs/react-a11y/rules/no-distracting-elements) | 2.2.2 | Distracting elements (marquee, blink) are not allowed | 💼 | | | | |
|
|
152
|
+
| [`aria-props`](https://eslint.interlace.tools/docs/react-a11y/rules/aria-props) | 4.1.2 | Invalid ARIA attribute | 💼 | | | | |
|
|
153
|
+
| [`aria-role`](https://eslint.interlace.tools/docs/react-a11y/rules/aria-role) | 4.1.2 | Invalid ARIA role | 💼 | | | | |
|
|
154
|
+
| [`role-has-required-aria-props`](https://eslint.interlace.tools/docs/react-a11y/rules/role-has-required-aria-props) | 4.1.2 | Role missing required aria props | 💼 | | | | |
|
|
155
|
+
| [`aria-unsupported-elements`](https://eslint.interlace.tools/docs/react-a11y/rules/aria-unsupported-elements) | 4.1.2 | Element does not support ARIA roles/props | 💼 | | | | |
|
|
156
|
+
| [`click-events-have-key-events`](https://eslint.interlace.tools/docs/react-a11y/rules/click-events-have-key-events) | 2.1.1 | onClick must be accompanied by onKeyUp/KeyDown | 💼 | | | | |
|
|
157
|
+
| [`heading-has-content`](https://eslint.interlace.tools/docs/react-a11y/rules/heading-has-content) | 1.3.1 | Headings must have content | 💼 | | | | |
|
|
158
|
+
| [`label-has-associated-control`](https://eslint.interlace.tools/docs/react-a11y/rules/label-has-associated-control) | 3.3.2 | Form label must be associated with a control | 💼 | | | | |
|
|
159
|
+
| [`tabindex-no-positive`](https://eslint.interlace.tools/docs/react-a11y/rules/tabindex-no-positive) | 2.4.3 | Avoid positive tabIndex | 💼 | | | | |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## AI-Optimized Messages
|
|
164
|
+
|
|
165
|
+
This plugin is optimized for ESLint's [Model Context Protocol (MCP)](https://eslint.org/docs/latest/use/mcp), enabling AI assistants like **Cursor**, **GitHub Copilot**, and **Claude** to:
|
|
166
|
+
|
|
167
|
+
- Understand the exact vulnerability type via CWE references
|
|
168
|
+
- Apply the correct fix using structured guidance
|
|
169
|
+
- Provide educational context to developers
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
src/components/Button.tsx
|
|
173
|
+
12:5 error 🔒 CWE-20 WCAG:4.1.2 CVSS:5.3 | Interactive element missing accessible name | CRITICAL [WCAG 2.1 A]
|
|
174
|
+
Fix: Add aria-label="Submit Order" or inner text | https://eslint.interlace.tools/...
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
// .cursor/mcp.json
|
|
179
|
+
{
|
|
180
|
+
"mcpServers": {
|
|
181
|
+
"eslint": {
|
|
182
|
+
"command": "npx",
|
|
183
|
+
"args": ["@eslint/mcp@latest"]
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
By providing this structured context (CWE, OWASP, Fix), we enable AI tools to **reason** about the security flaw rather than hallucinating. This allows Copilot/Cursor to suggest the _exact_ correct fix immediately.
|
|
190
|
+
|
|
191
|
+
## 🔗 Related ESLint Plugins
|
|
192
|
+
|
|
193
|
+
Part of the **Interlace ESLint Ecosystem** — AI-native security plugins with LLM-optimized error messages:
|
|
194
|
+
|
|
195
|
+
| Plugin | Downloads | Description |
|
|
196
|
+
| :----------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------ |
|
|
197
|
+
| [`eslint-plugin-secure-coding`](https://www.npmjs.com/package/eslint-plugin-secure-coding) | [](https://www.npmjs.com/package/eslint-plugin-secure-coding) | General security rules & OWASP guidelines. |
|
|
198
|
+
| [`eslint-plugin-pg`](https://www.npmjs.com/package/eslint-plugin-pg) | [](https://www.npmjs.com/package/eslint-plugin-pg) | PostgreSQL security & best practices. |
|
|
199
|
+
| [`eslint-plugin-crypto`](https://www.npmjs.com/package/eslint-plugin-crypto) | [](https://www.npmjs.com/package/eslint-plugin-crypto) | NodeJS Cryptography security rules. |
|
|
200
|
+
| [`eslint-plugin-jwt`](https://www.npmjs.com/package/eslint-plugin-jwt) | [](https://www.npmjs.com/package/eslint-plugin-jwt) | JWT security & best practices. |
|
|
201
|
+
| [`eslint-plugin-browser-security`](https://www.npmjs.com/package/eslint-plugin-browser-security) | [](https://www.npmjs.com/package/eslint-plugin-browser-security) | Browser-specific security & XSS prevention. |
|
|
202
|
+
| [`eslint-plugin-express-security`](https://www.npmjs.com/package/eslint-plugin-express-security) | [](https://www.npmjs.com/package/eslint-plugin-express-security) | Express.js security hardening rules. |
|
|
203
|
+
| [`eslint-plugin-lambda-security`](https://www.npmjs.com/package/eslint-plugin-lambda-security) | [](https://www.npmjs.com/package/eslint-plugin-lambda-security) | AWS Lambda security best practices. |
|
|
204
|
+
| [`eslint-plugin-nestjs-security`](https://www.npmjs.com/package/eslint-plugin-nestjs-security) | [](https://www.npmjs.com/package/eslint-plugin-nestjs-security) | NestJS security rules & patterns. |
|
|
205
|
+
| [`eslint-plugin-import-next`](https://www.npmjs.com/package/eslint-plugin-import-next) | [](https://www.npmjs.com/package/eslint-plugin-import-next) | Next-gen import sorting & architecture. |
|
|
206
|
+
|
|
207
|
+
## 📄 License
|
|
208
|
+
|
|
209
|
+
MIT © [Ofri Peretz](https://github.com/ofri-peretz)
|
|
210
|
+
|
|
211
|
+
<p align="center">
|
|
212
|
+
<a href="https://eslint.interlace.tools/docs/react-a11y"><img src="https://eslint.interlace.tools/images/og-react-a11y.png" alt="ESLint Interlace Plugin" width="300" /></a>
|
|
213
|
+
</p>
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "eslint-plugin-react-a11y",
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "React accessibility ESLint plugin with 37 LLM-optimized rules for WCAG 2.1 compliance. Provides structured error messages for AI assistants and auto-fix capabilities.",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"types": "./src/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./src/index.d.ts",
|
|
11
|
+
"default": "./src/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./types": {
|
|
14
|
+
"types": "./src/types/index.d.ts",
|
|
15
|
+
"default": "./src/types/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"author": "Ofri Peretz <ofriperetzdev@gmail.com>",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"homepage": "https://github.com/ofri-peretz/eslint#readme",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/ofri-peretz/eslint.git",
|
|
24
|
+
"directory": "packages/eslint-plugin-react-a11y"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/ofri-peretz/eslint/issues"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"src/",
|
|
34
|
+
"dist/",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE",
|
|
37
|
+
"CHANGELOG.md",
|
|
38
|
+
"AGENTS.md"
|
|
39
|
+
],
|
|
40
|
+
"keywords": [
|
|
41
|
+
"eslint",
|
|
42
|
+
"eslint-plugin",
|
|
43
|
+
"eslintplugin",
|
|
44
|
+
"interlace-quality",
|
|
45
|
+
"accessibility",
|
|
46
|
+
"a11y",
|
|
47
|
+
"react",
|
|
48
|
+
"wcag",
|
|
49
|
+
"wcag-2.1",
|
|
50
|
+
"aria",
|
|
51
|
+
"screen-reader",
|
|
52
|
+
"ada-compliance",
|
|
53
|
+
"section-508",
|
|
54
|
+
"llm-optimized",
|
|
55
|
+
"ai-assistant",
|
|
56
|
+
"auto-fix",
|
|
57
|
+
"typescript",
|
|
58
|
+
"linting",
|
|
59
|
+
"code-quality",
|
|
60
|
+
"ast",
|
|
61
|
+
"static-analysis",
|
|
62
|
+
"mcp",
|
|
63
|
+
"model-context-protocol",
|
|
64
|
+
"github-copilot",
|
|
65
|
+
"cursor-ai",
|
|
66
|
+
"claude-ai"
|
|
67
|
+
],
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=18.0.0"
|
|
70
|
+
},
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"tslib": "^2.3.0",
|
|
73
|
+
"@interlace/eslint-devkit": "*"
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@typescript-eslint/parser": "^8.46.2",
|
|
77
|
+
"@typescript-eslint/rule-tester": "^8.46.2"
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Ofri Peretz
|
|
3
|
+
* Licensed under the MIT License. Use of this source code is governed by the
|
|
4
|
+
* MIT license that can be found in the LICENSE file.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* eslint-plugin-react-a11y
|
|
8
|
+
*
|
|
9
|
+
* A comprehensive React accessibility ESLint plugin with 37 LLM-optimized rules
|
|
10
|
+
* for detecting and preventing accessibility violations in React/JSX code.
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - WCAG 2.1 Level A, AA, and AAA compliance
|
|
14
|
+
* - LLM-optimized error messages with fix suggestions
|
|
15
|
+
* - Auto-fix capabilities where safe
|
|
16
|
+
* - Structured context for AI assistants
|
|
17
|
+
*
|
|
18
|
+
* @see https://github.com/ofri-peretz/eslint#readme
|
|
19
|
+
*/
|
|
20
|
+
import type { TSESLint } from '@interlace/eslint-devkit';
|
|
21
|
+
/**
|
|
22
|
+
* Collection of all accessibility ESLint rules
|
|
23
|
+
*/
|
|
24
|
+
export declare const rules: Record<string, TSESLint.RuleModule<string, readonly unknown[]>>;
|
|
25
|
+
/**
|
|
26
|
+
* ESLint Plugin object
|
|
27
|
+
*/
|
|
28
|
+
export declare const plugin: TSESLint.FlatConfig.Plugin;
|
|
29
|
+
/**
|
|
30
|
+
* Preset configurations for accessibility rules
|
|
31
|
+
*/
|
|
32
|
+
export declare const configs: Record<string, TSESLint.FlatConfig.Config>;
|
|
33
|
+
/**
|
|
34
|
+
* Default export for ESLint plugin
|
|
35
|
+
*/
|
|
36
|
+
export default plugin;
|
|
37
|
+
/**
|
|
38
|
+
* Re-export types (will be created in types/index.ts)
|
|
39
|
+
*/
|
|
40
|
+
export * from './types/index';
|