Skip to content

Commit 2e13bb6

Browse files
fix: add eslint-plugin-jsx-a11y
1 parent 535784c commit 2e13bb6

File tree

4 files changed

+87
-2
lines changed

4 files changed

+87
-2
lines changed

knip.jsonc

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"eslint-plugin-import-x",
2424
"eslint-plugin-jsdoc",
2525
"eslint-plugin-jsonc",
26+
"eslint-plugin-jsx-a11y",
2627
"eslint-plugin-markdown",
2728
"eslint-plugin-n",
2829
"eslint-plugin-no-only-tests",

package.json

+5
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
"eslint-plugin-import-x": "4.3.1",
101101
"eslint-plugin-jsdoc": "50.3.1",
102102
"eslint-plugin-jsonc": "2.16.0",
103+
"eslint-plugin-jsx-a11y": "6.10.0",
103104
"eslint-plugin-markdown": "5.1.0",
104105
"eslint-plugin-n": "17.10.3",
105106
"eslint-plugin-no-only-tests": "3.3.0",
@@ -158,6 +159,7 @@
158159
"eslint-plugin-import-x": "*",
159160
"eslint-plugin-jsdoc": "*",
160161
"eslint-plugin-jsonc": "*",
162+
"eslint-plugin-jsx-a11y": "*",
161163
"eslint-plugin-markdown": "*",
162164
"eslint-plugin-n": "*",
163165
"eslint-plugin-no-only-tests": "*",
@@ -238,6 +240,9 @@
238240
"eslint-plugin-jsonc": {
239241
"optional": true
240242
},
243+
"eslint-plugin-jsx-a11y": {
244+
"optional": true
245+
},
241246
"eslint-plugin-markdown": {
242247
"optional": true
243248
},

pnpm-lock.yaml

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/configs/react.ts

+78-2
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ export async function react(
2424
): Promise<FlatConfigItem[]> {
2525
const { files, i18n, overrides, typescript, parserOptions } = options;
2626

27-
const [pluginReact, pluginReactHooks, pluginReactRefresh] = (await loadPackages([
27+
const [pluginReact, pluginReactHooks, pluginReactRefresh, pluginJsxA11y] = (await loadPackages([
2828
"@eslint-react/eslint-plugin",
2929
"eslint-plugin-react-hooks",
3030
"eslint-plugin-react-refresh",
31-
])) as [ESLint.Plugin, ESLint.Plugin, ESLint.Plugin];
31+
"eslint-plugin-jsx-a11y",
32+
])) as [ESLint.Plugin, ESLint.Plugin, ESLint.Plugin, ESLint.Plugin];
3233

3334
const parserTs = typescript ? await interopDefault(import("@typescript-eslint/parser")) : undefined;
3435

@@ -53,6 +54,7 @@ export async function react(
5354
plugins["@eslint-react/naming-convention"] ??
5455
assert.fail(`Failed to find "@eslint-react/naming-convention".`),
5556
"react-refresh": pluginReactRefresh,
57+
"jsx-a11y": pluginJsxA11y,
5658
},
5759
},
5860
{
@@ -138,6 +140,80 @@ export async function react(
138140
"react/prefer-shorthand-boolean": "error",
139141
"react/prefer-shorthand-fragment": "error",
140142

143+
"jsx-a11y/alt-text": "error",
144+
"jsx-a11y/anchor-has-content": "error",
145+
"jsx-a11y/anchor-is-valid": "error",
146+
"jsx-a11y/aria-activedescendant-has-tabindex": "error",
147+
"jsx-a11y/aria-props": "error",
148+
"jsx-a11y/aria-proptypes": "error",
149+
"jsx-a11y/aria-role": "error",
150+
"jsx-a11y/aria-unsupported-elements": "error",
151+
"jsx-a11y/autocomplete-valid": "error",
152+
"jsx-a11y/click-events-have-key-events": "error",
153+
"jsx-a11y/control-has-associated-label": [
154+
"off",
155+
{
156+
ignoreElements: ["audio", "canvas", "embed", "input", "textarea", "tr", "video"],
157+
ignoreRoles: [
158+
"grid",
159+
"listbox",
160+
"menu",
161+
"menubar",
162+
"radiogroup",
163+
"row",
164+
"tablist",
165+
"toolbar",
166+
"tree",
167+
"treegrid",
168+
],
169+
includeRoles: ["alert", "dialog"],
170+
},
171+
],
172+
"jsx-a11y/heading-has-content": "error",
173+
"jsx-a11y/html-has-lang": "error",
174+
"jsx-a11y/iframe-has-title": "error",
175+
"jsx-a11y/img-redundant-alt": "error",
176+
"jsx-a11y/interactive-supports-focus": [
177+
"error",
178+
{
179+
tabbable: [
180+
"button",
181+
"checkbox",
182+
"link",
183+
"progressbar",
184+
"searchbox",
185+
"slider",
186+
"spinbutton",
187+
"switch",
188+
"textbox",
189+
],
190+
},
191+
],
192+
"jsx-a11y/label-has-for": "off",
193+
"jsx-a11y/label-has-associated-control": "error",
194+
"jsx-a11y/media-has-caption": "error",
195+
"jsx-a11y/mouse-events-have-key-events": "error",
196+
"jsx-a11y/no-access-key": "error",
197+
"jsx-a11y/no-autofocus": "error",
198+
"jsx-a11y/no-distracting-elements": "error",
199+
"jsx-a11y/no-interactive-element-to-noninteractive-role": "error",
200+
"jsx-a11y/no-noninteractive-element-interactions": [
201+
"error",
202+
{
203+
body: ["onError", "onLoad"],
204+
iframe: ["onError", "onLoad"],
205+
img: ["onError", "onLoad"],
206+
},
207+
],
208+
"jsx-a11y/no-noninteractive-element-to-interactive-role": "error",
209+
"jsx-a11y/no-noninteractive-tabindex": "error",
210+
"jsx-a11y/no-redundant-roles": "error",
211+
"jsx-a11y/no-static-element-interactions": "error",
212+
"jsx-a11y/role-has-required-aria-props": "error",
213+
"jsx-a11y/role-supports-aria-props": "error",
214+
"jsx-a11y/scope": "error",
215+
"jsx-a11y/tabindex-no-positive": "error",
216+
141217
...(typescript
142218
? {
143219
"react/no-leaked-conditional-rendering": "error",

0 commit comments

Comments
 (0)