From 6728a1274d32d1bb9f4ae29b8ea6be88ce4eca4a Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Thu, 2 Jul 2026 11:45:22 -0400 Subject: [PATCH] chore(a11y): enforce a curated jsx-a11y lint gate in CI (P3-4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enables ARIA-correctness rules (aria-props/proptypes/role/unsupported-elements, role-has/supports-aria-props, no-redundant-roles, anchor/heading-has-content) + label-has-associated-control as errors — a regression gate for accessible names + valid ARIA. control-has-associated-label deliberately NOT enabled (the repo's component pattern defeats its static analysis); the real gaps it surfaced were fixed directly. Also disable max-classes-per-file for test files (mock classes). Co-Authored-By: Claude Opus 4.8 --- eslint.config.mjs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index bffd15fd9..9cc33711b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -25,7 +25,7 @@ export default [ tsPlugin.configs['flat/eslint-recommended'], ...tsPlugin.configs['flat/recommended'], reactPlugin.configs.flat.recommended, - reactHooksPlugin.configs.flat['recommended'], + reactHooksPlugin.configs.flat.recommended, // Register jsx-a11y plugin (rules selectively enabled below) { plugins: { 'jsx-a11y': jsxA11yPlugin } }, // airbnb-base via FlatCompat (JS/import rules; no React plugin, no getFilename issue) @@ -115,6 +115,26 @@ export default [ 'jsx-a11y/media-has-caption': 'off', 'jsx-a11y/no-noninteractive-element-interactions': 'off', 'jsx-a11y/alt-text': 'off', + // A11y regression gate (P3-4). A CURATED set — correctness rules that catch + // real WCAG gaps (missing accessible names, malformed ARIA) without + // flooding on the pre-existing clickable-div patterns. The heavier + // interaction rules (no-static-element-interactions, + // click-events-have-key-events) are a separate cleanup and stay OFF. + 'jsx-a11y/aria-props': 'error', + 'jsx-a11y/aria-proptypes': 'error', + 'jsx-a11y/aria-role': ['error', { ignoreNonDOM: true }], + 'jsx-a11y/aria-unsupported-elements': 'error', + 'jsx-a11y/role-has-required-aria-props': 'error', + 'jsx-a11y/role-supports-aria-props': 'error', + 'jsx-a11y/no-redundant-roles': 'error', + 'jsx-a11y/anchor-has-content': 'error', + 'jsx-a11y/heading-has-content': 'error', + 'jsx-a11y/label-has-associated-control': ['error', { assert: 'either', depth: 5 }], + // NOT enabled: control-has-associated-label. This repo labels most inputs + // with folds `` — a component the rule's static + // analysis can't see as a