eslint-plugin-a11y 1.0.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/LICENSE ADDED
@@ -0,0 +1,45 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Marlon Maniti
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
+
23
+ ## API Reference
24
+
25
+ ### A11yChecker
26
+
27
+ #### `check(element: Element): Promise<A11yResults>`
28
+ Performs all accessibility checks on the given element.
29
+
30
+ #### `checkImageAlt(element: Element): A11yViolation[]`
31
+ Checks images for proper alt attributes.
32
+
33
+ #### `checkLinkText(element: Element): A11yViolation[]`
34
+ Validates link text for accessibility.
35
+
36
+ #### `checkButtonLabel(element: Element): A11yViolation[]`
37
+ Ensures buttons have proper labels.
38
+
39
+ #### `checkFormLabels(element: Element): A11yViolation[]`
40
+ Validates form control label associations.
41
+
42
+ #### `checkHeadingOrder(element: Element): A11yViolation[]`
43
+ Checks heading hierarchy.
44
+
45
+ ### Types
package/README.md ADDED
@@ -0,0 +1,596 @@
1
+ # eslint-plugin-a11y
2
+
3
+ > **DEPRECATED:** This package has been renamed to [`eslint-plugin-a11y`](https://www.npmjs.com/package/eslint-plugin-a11y).
4
+ > Run: `npm install --save-dev eslint-plugin-a11y`
5
+ > See the [migration guide](./docs/MIGRATION_TO_A11Y.md) for details.
6
+
7
+ > **Catch accessibility issues in your editor, not in production.** Zero-config ESLint plugin + programmatic API for React, Vue, and JSX.
8
+
9
+ [![npm version](https://img.shields.io/npm/v/eslint-plugin-a11y.svg)](https://www.npmjs.com/package/eslint-plugin-a11y)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
12
+
13
+ ## Why a11y?
14
+
15
+ - ✅ **Zero config** - Works out of the box with React, Vue, and JSX
16
+ - ✅ **Real-time feedback** - Catch issues in your editor, not in production
17
+ - ✅ **43 accessibility rules** - Covers images, forms, buttons, landmarks, ARIA, focus, and more
18
+ - ✅ **Editor suggestions** - Get actionable fixes directly in your editor
19
+ - ✅ **Dual API** - Use as ESLint plugin OR programmatic API
20
+ - ✅ **Large project ready** - Minimal preset for incremental adoption
21
+ - ✅ **Framework agnostic** - Works with React, Vue, Preact, Solid, and more
22
+ - ✅ **Fast & lightweight** - Pure AST validation, 35KB bundle, zero memory issues
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install --save-dev eslint-plugin-a11y
28
+ ```
29
+
30
+ ### Peer Dependencies
31
+
32
+ - `eslint` (>=8.0.0) - Required for ESLint plugin
33
+ - `vue-eslint-parser` (>=9.0.0) - Optional, only needed for Vue support
34
+ - `jsdom` (>=23.0.0) - Optional, only needed for A11yChecker core library (programmatic API)
35
+
36
+ **Note:** The ESLint plugin does NOT use jsdom. It performs pure AST validation for maximum performance. jsdom is only required if you use the programmatic A11yChecker API in your tests.
37
+
38
+ ## Quick Start
39
+
40
+ ### Option 1: ESLint Plugin (Recommended)
41
+
42
+ Add to your `.eslintrc.js` or `.eslintrc.json`:
43
+
44
+ ```javascript
45
+ // .eslintrc.js
46
+ module.exports = {
47
+ plugins: ['a11y'],
48
+ extends: ['plugin:a11y/recommended']
49
+ }
50
+ ```
51
+
52
+ Or for React/JSX projects:
53
+
54
+ ```javascript
55
+ module.exports = {
56
+ plugins: ['a11y'],
57
+ extends: ['plugin:a11y/react']
58
+ }
59
+ ```
60
+
61
+ That's it! Start catching accessibility issues immediately in your editor.
62
+
63
+ ### Option 2: Programmatic API
64
+
65
+ Use in your tests:
66
+
67
+ ```typescript
68
+ import { A11yChecker } from 'eslint-plugin-a11y/core'
69
+
70
+ // Test a DOM element for accessibility violations
71
+ const violations = await A11yChecker.check(element)
72
+
73
+ // Or check specific patterns
74
+ const imageViolations = A11yChecker.checkImageAlt(element)
75
+ const buttonViolations = A11yChecker.checkButtonLabel(element)
76
+ ```
77
+
78
+ ## ESLint Plugin vs Programmatic API
79
+
80
+ **Use ESLint Plugin when:**
81
+ - ✅ You want real-time feedback in your editor
82
+ - ✅ You want to catch issues during development
83
+ - ✅ You want CI/CD integration to prevent commits with violations
84
+ - ✅ You want team-wide enforcement
85
+
86
+ **Use Programmatic API when:**
87
+ - ✅ You want to write specific accessibility tests
88
+ - ✅ You need to test dynamically generated DOM
89
+ - ✅ You want custom reporting or analytics
90
+ - ✅ You're writing integration/E2E tests
91
+
92
+ **You can use both!** Many teams use ESLint plugin for development and programmatic API for comprehensive test coverage.
93
+
94
+ ## Configuration Options
95
+
96
+ ### Available Presets
97
+
98
+ **Classic Config (.eslintrc.js):**
99
+ - `plugin:a11y/minimal` - Only 3 critical rules (best for large projects)
100
+ - `plugin:a11y/recommended` - Balanced approach (default)
101
+ - `plugin:a11y/strict` - All rules as errors
102
+ - `plugin:a11y/react` - Optimized for React/JSX
103
+ - `plugin:a11y/vue` - Optimized for Vue SFC
104
+
105
+ **Flat Config (eslint.config.js) - ESLint v9+:**
106
+ - `flat/recommended` - Rules only (minimal assumptions)
107
+ - `flat/recommended-react` - Rules + React parser
108
+ - `flat/react` - Full React setup
109
+ - `flat/vue` - Full Vue setup
110
+ - `flat/minimal` - Minimal rules only
111
+ - `flat/strict` - All rules as errors
112
+
113
+ ### Framework-Specific Setup
114
+
115
+ **React/JSX:**
116
+ ```javascript
117
+ module.exports = {
118
+ parser: '@typescript-eslint/parser',
119
+ parserOptions: {
120
+ ecmaFeatures: { jsx: true }
121
+ },
122
+ plugins: ['a11y'],
123
+ extends: ['plugin:a11y/react']
124
+ }
125
+ ```
126
+
127
+ **Vue:**
128
+ ```javascript
129
+ module.exports = {
130
+ parser: 'vue-eslint-parser',
131
+ parserOptions: {
132
+ parser: '@typescript-eslint/parser'
133
+ },
134
+ plugins: ['a11y'],
135
+ extends: ['plugin:a11y/vue']
136
+ }
137
+ ```
138
+
139
+ ### Ignoring Rules
140
+
141
+ **Ignore a single line:**
142
+ ```jsx
143
+ // eslint-disable-next-line a11y/image-alt
144
+ <img src="decorative.jpg" alt="" />
145
+ ```
146
+
147
+ **Ignore an entire file:**
148
+ ```jsx
149
+ /* eslint-disable a11y/heading-order */
150
+ ```
151
+
152
+ **Ignore directories:**
153
+ ```javascript
154
+ module.exports = {
155
+ plugins: ['a11y'],
156
+ extends: ['plugin:a11y/recommended'],
157
+ ignorePatterns: [
158
+ '**/node_modules/**',
159
+ '**/dist/**',
160
+ '**/*.test.{js,ts,jsx,tsx}'
161
+ ]
162
+ }
163
+ ```
164
+
165
+ ### Rule Options
166
+
167
+ Many rules support configuration options for fine-tuned control:
168
+
169
+ **image-alt - Decorative images:**
170
+ ```javascript
171
+ {
172
+ 'a11y/image-alt': ['error', {
173
+ allowMissingAltOnDecorative: true,
174
+ decorativeMatcher: {
175
+ markerAttributes: ['data-decorative']
176
+ }
177
+ }]
178
+ }
179
+ ```
180
+
181
+ **link-text - Custom denylist:**
182
+ ```javascript
183
+ {
184
+ 'a11y/link-text': ['warn', {
185
+ denylist: ['click here', 'read more'],
186
+ caseInsensitive: true
187
+ }]
188
+ }
189
+ ```
190
+
191
+ **heading-order - Skip tolerance:**
192
+ ```javascript
193
+ {
194
+ 'a11y/heading-order': ['warn', {
195
+ allowSameLevel: true,
196
+ maxSkip: 2
197
+ }]
198
+ }
199
+ ```
200
+
201
+ See [Configuration Guide](./docs/CONFIGURATION.md) for all options.
202
+
203
+ ### Component Mapping
204
+
205
+ Map your design-system components to native HTML elements:
206
+
207
+ ```javascript
208
+ module.exports = {
209
+ plugins: ['a11y'],
210
+ extends: ['plugin:a11y/recommended'],
211
+ settings: {
212
+ 'a11y': {
213
+ components: {
214
+ Link: 'a', // Treat <Link> as <a>
215
+ Button: 'button', // Treat <Button> as <button>
216
+ Image: 'img' // Treat <Image> as <img>
217
+ },
218
+ polymorphicPropNames: ['as', 'component'] // Support <Link as="a">
219
+ }
220
+ }
221
+ }
222
+ ```
223
+
224
+ Now rules apply to your components:
225
+ ```jsx
226
+ <Link href="/about">Click here</Link> // ⚠️ Warning: nonDescriptive
227
+ <Button></Button> // ❌ Error: missingLabel
228
+ ```
229
+
230
+ ### Quick start with ESLint flat config (v9+)
231
+
232
+ ```js
233
+ // eslint.config.js
234
+ import js from '@eslint/js'
235
+ import tseslint from 'typescript-eslint'
236
+ import react from 'eslint-plugin-react'
237
+ import testA11y from 'eslint-plugin-a11y'
238
+
239
+ export default [
240
+ js.configs.recommended,
241
+ ...tseslint.configs.recommended,
242
+
243
+ {
244
+ plugins: {
245
+ react,
246
+ 'a11y': testA11y
247
+ },
248
+ languageOptions: {
249
+ parserOptions: {
250
+ ecmaVersion: 2022,
251
+ sourceType: 'module',
252
+ ecmaFeatures: { jsx: true }
253
+ }
254
+ },
255
+ ...testA11y.configs['flat/recommended-react']
256
+ },
257
+
258
+ // Optional: Vue-specific rules only on .vue files
259
+ {
260
+ files: ['**/*.vue'],
261
+ languageOptions: {
262
+ parser: 'vue-eslint-parser',
263
+ parserOptions: {
264
+ parser: '@typescript-eslint/parser',
265
+ ecmaVersion: 2022,
266
+ sourceType: 'module'
267
+ }
268
+ },
269
+ plugins: {
270
+ 'a11y': testA11y
271
+ },
272
+ ...testA11y.configs['flat/vue']
273
+ }
274
+ ]
275
+ ```
276
+
277
+ These presets mirror the classic `.eslintrc` presets and are the easiest way to drop `eslint-plugin-a11y` into a modern ESLint v9+ setup, alongside `@eslint/js`, `typescript-eslint`, and `eslint-plugin-react`.
278
+
279
+ See [Configuration Guide](./docs/CONFIGURATION.md) for more flat-config examples and advanced setups.
280
+
281
+ ## Editor Suggestions
282
+
283
+ Many rules provide **suggestions** that appear in your editor, allowing you to quickly fix issues:
284
+
285
+ - **iframe-title**: Suggests adding `title=""` placeholder
286
+ - **button-label**: Suggests adding `aria-label=""` for icon-only buttons
287
+ - **link-text**: Suggests replacing non-descriptive text
288
+ - **heading-order**: Suggests correct heading level
289
+
290
+ In VS Code and other editors with ESLint support, suggestions appear as Quick Fix options (Cmd/Ctrl + .).
291
+
292
+ **Note**: Suggestions are **not** autofixes - they require manual review and approval.
293
+
294
+ ## ESLint Rules
295
+
296
+ The plugin provides **43 accessibility rules**:
297
+
298
+ **Core rules:**
299
+ - `a11y/image-alt` - Enforce images, `input[type=image]`, and `area` elements have alt attributes
300
+ - `a11y/button-label` - Enforce buttons have labels
301
+ - `a11y/link-text` - Enforce links have descriptive text
302
+ - `a11y/form-label` - Enforce form controls have labels
303
+ - `a11y/heading-order` - Enforce proper heading hierarchy
304
+ - `a11y/iframe-title` - Enforce iframes have title attributes
305
+ - `a11y/fieldset-legend` - Enforce fieldsets have legend elements
306
+ - `a11y/table-structure` - Enforce tables have proper structure
307
+ - `a11y/details-summary` - Enforce details elements have summary
308
+ - `a11y/video-captions` - Enforce video elements have caption tracks
309
+ - `a11y/audio-captions` - Enforce audio elements have tracks or transcripts
310
+ - `a11y/landmark-roles` - Enforce proper use of landmark elements
311
+ - `a11y/dialog-modal` - Enforce dialog elements have proper accessibility attributes
312
+ - `a11y/aria-validation` - Validate ARIA roles, properties, and ID references (AST-first)
313
+ - `a11y/semantic-html` - Enforce proper use of semantic HTML elements (AST-first)
314
+ - `a11y/form-validation` - Validate form validation patterns (AST-first)
315
+
316
+ **Attribute & document rules:**
317
+ - `a11y/no-access-key` - Disallow accessKey on elements
318
+ - `a11y/no-autofocus` - Disallow autoFocus
319
+ - `a11y/tabindex-no-positive` - Disallow positive tabIndex
320
+ - `a11y/no-distracting-elements` - Disallow blink and marquee
321
+ - `a11y/lang` - Enforce valid lang attribute values
322
+ - `a11y/html-has-lang` - Enforce html element has lang attribute
323
+
324
+ **Focusable & ARIA rules:**
325
+ - `a11y/no-aria-hidden-on-focusable` - Disallow aria-hidden on focusable elements
326
+ - `a11y/no-role-presentation-on-focusable` - Disallow role="presentation" on focusable elements
327
+ - `a11y/no-interactive-element-to-noninteractive-role` - Disallow role="none/presentation" on interactive elements (button, a, input, etc.)
328
+ - `a11y/no-noninteractive-element-to-interactive-role` - Disallow interactive roles on non-interactive elements without keyboard support
329
+ - `a11y/no-redundant-roles` - Disallow explicit roles that match the element's implicit ARIA role
330
+ - `a11y/prefer-tag-over-role` - Prefer semantic native HTML elements over ARIA role attributes on generic elements
331
+ - `a11y/control-has-associated-label` - Enforce ARIA-role interactive controls have an accessible label
332
+ - `a11y/scope` - Enforce valid use of the scope attribute on `<th>` elements
333
+ - `a11y/aria-activedescendant-has-tabindex` - Enforce aria-activedescendant targets are focusable
334
+
335
+ **Event & keyboard rules:**
336
+ - `a11y/click-events-have-key-events` - Enforce onClick has keyboard equivalent
337
+ - `a11y/mouse-events-have-key-events` - Enforce mouse handlers have keyboard equivalent
338
+ - `a11y/no-static-element-interactions` - Disallow static handlers on non-interactive elements
339
+ - `a11y/no-noninteractive-element-interactions` - Disallow interactive handlers on non-interactive elements
340
+ - `a11y/interactive-supports-focus` - Enforce interactive elements are focusable
341
+ - `a11y/no-noninteractive-tabindex` - Disallow tabindex on non-interactive elements
342
+
343
+ **Content & media rules:**
344
+ - `a11y/heading-has-content` - Enforce headings have content
345
+ - `a11y/img-redundant-alt` - Enforce img alt does not contain redundant words
346
+ - `a11y/anchor-ambiguous-text` - Enforce link text is not generic
347
+ - `a11y/anchor-is-valid` - Enforce anchors have valid href (not empty, `#`, or `javascript:`)
348
+ - `a11y/accessible-emoji` - Enforce emoji have accessible labels
349
+ - `a11y/autocomplete-valid` - Enforce autocomplete attribute is valid
350
+
351
+ ## Programmatic API
352
+
353
+ ### A11yChecker Methods
354
+
355
+ ```typescript
356
+ import { A11yChecker } from 'eslint-plugin-a11y/core'
357
+
358
+ // Comprehensive check
359
+ const results = await A11yChecker.check(element)
360
+
361
+ // Individual checks
362
+ A11yChecker.checkImageAlt(element)
363
+ A11yChecker.checkButtonLabel(element)
364
+ A11yChecker.checkLinkText(element)
365
+ A11yChecker.checkFormLabels(element)
366
+ A11yChecker.checkHeadingOrder(element)
367
+ A11yChecker.checkIframeTitle(element)
368
+ A11yChecker.checkFieldsetLegend(element)
369
+ A11yChecker.checkTableStructure(element)
370
+ A11yChecker.checkDetailsSummary(element)
371
+ A11yChecker.checkVideoCaptions(element)
372
+ A11yChecker.checkAudioCaptions(element)
373
+ A11yChecker.checkLandmarks(element)
374
+ A11yChecker.checkDialogModal(element)
375
+
376
+ // Advanced checks (available in core library)
377
+ A11yChecker.checkAriaRoles(element)
378
+ A11yChecker.checkAriaProperties(element)
379
+ A11yChecker.checkAriaRelationships(element)
380
+ A11yChecker.checkAccessibleName(element)
381
+ A11yChecker.checkCompositePatterns(element)
382
+ A11yChecker.checkSemanticHTML(element)
383
+ A11yChecker.checkFormValidationMessages(element)
384
+ ```
385
+
386
+ ### Types
387
+
388
+ ```typescript
389
+ interface A11yViolation {
390
+ id: string
391
+ description: string
392
+ element: Element
393
+ impact: 'critical' | 'serious' | 'moderate' | 'minor'
394
+ }
395
+
396
+ interface A11yResults {
397
+ violations: A11yViolation[]
398
+ }
399
+ ```
400
+
401
+ ## Examples
402
+
403
+ ### React Component
404
+
405
+ ```tsx
406
+ // ❌ ESLint will catch this
407
+ function MyComponent() {
408
+ return (
409
+ <div>
410
+ <img src="photo.jpg" /> {/* Missing alt */}
411
+ <button></button> {/* No label */}
412
+ </div>
413
+ )
414
+ }
415
+
416
+ // ✅ Fixed
417
+ function MyComponent() {
418
+ return (
419
+ <div>
420
+ <img src="photo.jpg" alt="A beautiful landscape" />
421
+ <button aria-label="Close menu">×</button>
422
+ </div>
423
+ )
424
+ }
425
+ ```
426
+
427
+ ### Vue Component
428
+
429
+ ```vue
430
+ <!-- ❌ ESLint will catch this -->
431
+ <template>
432
+ <img src="photo.jpg" />
433
+ <button></button>
434
+ </template>
435
+
436
+ <!-- ✅ Fixed -->
437
+ <template>
438
+ <img src="photo.jpg" alt="A beautiful landscape" />
439
+ <button aria-label="Close menu">×</button>
440
+ </template>
441
+ ```
442
+
443
+ ### Using in Tests
444
+
445
+ ```typescript
446
+ import { render } from '@testing-library/react'
447
+ import { A11yChecker } from 'eslint-plugin-a11y/core'
448
+
449
+ test('component is accessible', async () => {
450
+ const { container } = render(<MyComponent />)
451
+ const results = await A11yChecker.check(container)
452
+ expect(results.violations).toHaveLength(0)
453
+ })
454
+ ```
455
+
456
+ ## Large Projects
457
+
458
+ For large codebases, start with minimal rules:
459
+
460
+ ```javascript
461
+ // .eslintrc.js
462
+ module.exports = {
463
+ plugins: ['a11y'],
464
+ extends: ['plugin:a11y/minimal'],
465
+ ignorePatterns: ['**/node_modules/**', '**/dist/**']
466
+ }
467
+ ```
468
+
469
+ See [Large Project Setup Guide](./docs/LARGE_PROJECTS.md) for incremental adoption strategies.
470
+
471
+ ## Progress Display (Optional)
472
+
473
+ The plugin includes a progress-aware ESLint wrapper that shows which files are being linted, similar to Vite's test output.
474
+
475
+ ### Quick Setup for Next.js Projects
476
+
477
+ Replace `next lint` with the progress wrapper in your `package.json`:
478
+
479
+ ```json
480
+ {
481
+ "scripts": {
482
+ "lint": "node node_modules/eslint-plugin-a11y/bin/eslint-with-progress.js",
483
+ "lint:fix": "node node_modules/eslint-plugin-a11y/bin/eslint-with-progress.js --fix"
484
+ }
485
+ }
486
+ ```
487
+
488
+ Or use the binary directly:
489
+
490
+ ```bash
491
+ npx eslint-with-progress
492
+ ```
493
+
494
+ ### What You Get
495
+
496
+ - ✅ **Progress display** - Shows "Linting files..." message
497
+ - ✅ **File-by-file results** with line numbers
498
+ - ✅ **Summary** showing total files, errors, and warnings
499
+ - ✅ **Color-coded** output (errors in red, warnings in yellow)
500
+ - ✅ **Timing information**
501
+
502
+ Example output:
503
+ ```
504
+ Linting files...
505
+
506
+ src/components/Button.tsx
507
+ 5:12 ✖ Image missing alt attribute (a11y/image-alt)
508
+ 8:3 ⚠ Button should have accessible label (a11y/button-label)
509
+
510
+ ────────────────────────────────────────────────────────────
511
+
512
+ Summary: 15 files linted • 2 errors • 5 warnings
513
+
514
+ Completed in 1.23s
515
+ ```
516
+
517
+ **Note:** This is optional. Your plugin rules work automatically with `next lint` - this just adds progress display.
518
+
519
+ ## Performance
520
+
521
+ For large projects, use ESLint caching:
522
+
523
+ ```bash
524
+ npx eslint . --cache
525
+ ```
526
+
527
+ See [Performance Guide](./docs/PERFORMANCE.md) for optimization tips.
528
+
529
+ ## Framework Support
530
+
531
+ - ✅ **React/JSX** - Full support via JSX AST
532
+ - ✅ **Vue** - Full support via vue-eslint-parser
533
+ - ✅ **HTML Strings** - Support for template literals (requires jsdom for core API)
534
+ - ✅ **Any JSX-based framework** - Preact, Solid, etc.
535
+
536
+ ## Documentation
537
+
538
+ - [Configuration Guide](./docs/CONFIGURATION.md) - ESLint plugin configuration options, rule options, component mapping
539
+ - [Migration Guide](./docs/MIGRATION_FROM_JSX_A11Y.md) - Migrate from eslint-plugin-jsx-a11y
540
+ - [Large Project Setup Guide](./docs/LARGE_PROJECTS.md) - Incremental adoption strategies
541
+ - [Performance Guide](./docs/PERFORMANCE.md) - Performance optimization tips
542
+ - [ESLint Plugin Guide](./docs/ESLINT_PLUGIN.md) - Complete ESLint plugin documentation
543
+ - [Vue Usage Guide](./docs/VUE_USAGE.md) - Vue-specific setup and examples
544
+ - [Examples](./docs/EXAMPLES.md) - Real-world code examples
545
+ - [Troubleshooting Guide](./docs/TROUBLESHOOTING.md) - Common issues and solutions
546
+ - [JSDOM Guide](./docs/JSDOM.md) - When and how to use jsdom
547
+
548
+ ## How It Compares
549
+
550
+ ### When to use this vs other a11y tools?
551
+
552
+ - **vs `eslint-plugin-jsx-a11y`**: Similar JSX accessibility coverage, plus Vue SFC support, flat-config presets, and a matching runtime `A11yChecker` API. You can run both plugins side by side and selectively disable overlapping rules in either one.
553
+ - **vs `eslint-plugin-vuejs-accessibility`**: This plugin covers both Vue templates *and* JSX/TSX with a single rule set, which is useful in mixed React/Vue or design-system-heavy codebases.
554
+ - **vs runtime-only tools (e.g. `@axe-core/react`)**: `a11y` focuses on **static**, editor-time feedback and CI linting, while the runtime A11yChecker API complements it for dynamic DOM testing.
555
+
556
+ For rule-by-rule mapping from `eslint-plugin-jsx-a11y` to `eslint-plugin-a11y`, see the [Migration Guide](./docs/MIGRATION_FROM_JSX_A11Y.md).
557
+
558
+ ### Feature comparison
559
+
560
+ | Feature | a11y | eslint-plugin-jsx-a11y | @axe-core/react |
561
+ |---------|--------------|------------------------|-----------------|
562
+ | Zero config | ✅ | ❌ | ❌ |
563
+ | Vue support | ✅ | ❌ | ❌ |
564
+ | Programmatic API | ✅ | ❌ | ✅ |
565
+ | Editor integration | ✅ | ✅ | ❌ |
566
+ | Large project ready | ✅ | ⚠️ | ⚠️ |
567
+ | Framework agnostic | ✅ | React only | React only |
568
+
569
+ ## FAQ
570
+
571
+ - **Does this replace `eslint-plugin-jsx-a11y`?**
572
+ Not necessarily. It can replace it in many React-only projects, but it also adds Vue SFC support, flat-config presets, and a runtime A11yChecker API. You can also run both plugins side by side and disable overlapping rules where needed.
573
+
574
+ - **Can I run `eslint-plugin-a11y` and `eslint-plugin-jsx-a11y` together?**
575
+ Yes. Add both plugins to your config and then selectively turn off overlapping rules in one or the other. The [Migration Guide](./docs/MIGRATION_FROM_JSX_A11Y.md) shows rule mappings and suggestions.
576
+
577
+ - **Does it support ESLint v9 flat config?**
578
+ Yes. All presets have `flat/*` equivalents (for example, `flat/recommended`, `flat/recommended-react`, `flat/vue`, `flat/minimal`, `flat/strict`). See the flat-config quick start above or the [Configuration Guide](./docs/CONFIGURATION.md).
579
+
580
+ - **Does it work with Vue Single File Components (SFC)?**
581
+ Yes. Install `vue-eslint-parser` and use the `vue` presets (classic or `flat/vue`). The flat-config example above shows how to scope Vue rules to `**/*.vue` files.
582
+
583
+ - **Why does it warn on dynamic `alt`/text instead of erroring?**
584
+ Dynamic attributes (like `alt={altText}`) cannot be fully validated statically. The plugin treats them as warnings by default and expects you to cover them via runtime checks using the A11yChecker API or other testing tools.
585
+
586
+ ## Contributing
587
+
588
+ Contributions are welcome! After cloning, `npm install` runs the `prepare` script (build + ContextKit git hooks; hooks live in `.contextkit/hooks/`). Please see the [contributing guidelines](CONTRIBUTING.md) for more information.
589
+
590
+ ## Author
591
+
592
+ Marlon Maniti (https://github.com/nolrm)
593
+
594
+ ## License
595
+
596
+ MIT