From 59cf5241ed9d9cdad498ed7a7357d83dd65d0bfa Mon Sep 17 00:00:00 2001 From: Arun Tyagi Date: Wed, 14 Jan 2026 14:07:23 +0530 Subject: [PATCH 1/8] integrate A11y react plugin --- .../code-analyzer-eslint-engine/package.json | 4 +- .../src/base-config.ts | 9 + .../code-analyzer-eslint-engine/src/config.ts | 4 +- .../src/rule-mappings.ts | 2 + .../src/rule-mappings/constants.ts | 1 + .../src/rule-mappings/react-jsx-a11y.ts | 172 ++++++++++++++++++ 6 files changed, 189 insertions(+), 3 deletions(-) create mode 100644 packages/code-analyzer-eslint-engine/src/rule-mappings/react-jsx-a11y.ts diff --git a/packages/code-analyzer-eslint-engine/package.json b/packages/code-analyzer-eslint-engine/package.json index 147c903f..1c1072d6 100644 --- a/packages/code-analyzer-eslint-engine/package.json +++ b/packages/code-analyzer-eslint-engine/package.json @@ -28,6 +28,7 @@ "eslint": "^9.39.2", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jest": "^29.5.0", + "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^7.0.1", "globals": "^16.5.0", @@ -36,6 +37,7 @@ "typescript-eslint": "^8.50.0" }, "devDependencies": { + "@types/eslint-plugin-jsx-a11y": "^6.10.1", "@types/jest": "^30.0.0", "@types/semver": "^7.7.1", "@types/unzipper": "^0.10.11", @@ -79,4 +81,4 @@ "!src/index.ts" ] } -} \ No newline at end of file +} diff --git a/packages/code-analyzer-eslint-engine/src/base-config.ts b/packages/code-analyzer-eslint-engine/src/base-config.ts index 4cb58a84..29c4a91c 100644 --- a/packages/code-analyzer-eslint-engine/src/base-config.ts +++ b/packages/code-analyzer-eslint-engine/src/base-config.ts @@ -6,6 +6,7 @@ import salesforceEslintConfigLwc from "@salesforce/eslint-config-lwc"; import sldsEslintPlugin from "@salesforce-ux/eslint-plugin-slds"; import eslintPluginReact from "eslint-plugin-react"; import eslintPluginReactHooks from "eslint-plugin-react-hooks"; +import eslintPluginJsxA11y from "eslint-plugin-jsx-a11y"; import {ESLintEngineConfig} from "./config"; import globals from "globals"; @@ -226,6 +227,8 @@ export class BaseConfigFactory { // These rules are not needed for React 17+ which is now the standard (released Oct 2020) const jsxRuntimeConfig = eslintPluginReact.configs.flat['jsx-runtime']; + + return [ // React all rules config { @@ -255,6 +258,12 @@ export class BaseConfigFactory { 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn' } + }, + // jsx-a11y plugin config + { + ...(((eslintPluginJsxA11y as unknown) as { flatConfigs?: any, configs?: any }).flatConfigs?.recommended + ?? ((eslintPluginJsxA11y as unknown) as { flatConfigs?: any, configs?: any }).configs?.['flat/recommended']), + files: filePatterns } ]; } diff --git a/packages/code-analyzer-eslint-engine/src/config.ts b/packages/code-analyzer-eslint-engine/src/config.ts index d8af0198..f3d8e293 100644 --- a/packages/code-analyzer-eslint-engine/src/config.ts +++ b/packages/code-analyzer-eslint-engine/src/config.ts @@ -70,7 +70,7 @@ export const DEFAULT_CONFIG: ESLintEngineConfig = { disable_lwc_base_config: false, disable_slds_base_config: false, disable_typescript_base_config: false, - disable_react_base_config: true, // Gated for now - will change to false when released + disable_react_base_config: false, // Gated for now - will change to false when released file_extensions: { javascript: ['.js', '.cjs', '.mjs', '.jsx'], typescript: ['.ts', '.tsx'], @@ -162,7 +162,7 @@ export function validateAndNormalizeConfig(configValueExtractor: ConfigValueExtr disable_typescript_base_config: eslintConfigValueExtractor.extractBooleanValue('disable_typescript_base_config'), // React support is gated - always force to true regardless of customer config // TODO: Change to eslintConfigValueExtractor.extractBooleanValue('disable_react_base_config') when released - disable_react_base_config: true, + disable_react_base_config: false, file_extensions: eslintConfigValueExtractor.extractFileExtensionsValue(), }; } diff --git a/packages/code-analyzer-eslint-engine/src/rule-mappings.ts b/packages/code-analyzer-eslint-engine/src/rule-mappings.ts index e479b256..0af87172 100644 --- a/packages/code-analyzer-eslint-engine/src/rule-mappings.ts +++ b/packages/code-analyzer-eslint-engine/src/rule-mappings.ts @@ -5,6 +5,7 @@ import {RULE_MAPPINGS_TYPESCRIPT_ESLINT} from "./rule-mappings/typescript-eslint import {RULE_MAPPINGS_SLDS_HTML} from "./rule-mappings/slds-html"; import {RULE_MAPPINGS_SLDS_CSS} from "./rule-mappings/slds-css"; import {RULE_MAPPINGS_REACT} from "./rule-mappings/react"; +import {RULE_MAPPINGS_REACT_A11Y} from "./rule-mappings/react-jsx-a11y"; export const RULE_MAPPINGS: Record = { ...RULE_MAPPINGS_ESLINT_BASE, @@ -13,4 +14,5 @@ export const RULE_MAPPINGS: Record = { + "jsx-a11y/alt-text": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/anchor-has-content": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/anchor-is-valid": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/aria-activedescendant-has-tabindex": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/aria-props": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/aria-proptypes": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/aria-role": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/aria-unsupported-elements": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/autocomplete-valid": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/click-events-have-key-events": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/heading-has-content": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/html-has-lang": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/iframe-has-title": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/img-redundant-alt": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/interactive-supports-focus": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/label-has-associated-control": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/media-has-caption": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/mouse-events-have-key-events": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-access-key": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-autofocus": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-distracting-elements": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-interactive-element-to-noninteractive-role": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-noninteractive-element-interactions": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-noninteractive-element-to-interactive-role": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-noninteractive-tabindex": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-redundant-roles": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-static-element-interactions": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/role-has-required-aria-props": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/role-supports-aria-props": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/scope": { + severity: SeverityLevel.Moderate, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/tabindex-no-positive": { + severity: SeverityLevel.High, + tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, +}; + +// All remaining rules not in the recommended config +export const RULE_MAPPINGS_REACT_A11Y_NOT_RECOMMENDED: Record = { + "jsx-a11y/accessible-emoji": { // DEPRECATED + severity: SeverityLevel.Low, + tags: [ REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/anchor-ambiguous-text": { + severity: SeverityLevel.Moderate, + tags: [ REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/control-has-associated-label": { + severity: SeverityLevel.Low, + tags: [ REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/label-has-for": { // DEPRECATED + severity: SeverityLevel.Low, + tags: [ REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/lang": { + severity: SeverityLevel.Moderate, + tags: [ REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-aria-hidden-on-focusable": { + severity: SeverityLevel.Moderate, + tags: [ REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/no-onchange": { // DEPRECATED + severity: SeverityLevel.Low, + tags: [ REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, + "jsx-a11y/prefer-tag-over-role": { + severity: SeverityLevel.Low, + tags: [ REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] + }, +}; + +export const RULE_MAPPINGS_REACT_A11Y: Record = { + ...RULE_MAPPINGS_REACT_A11Y_RECOMMENDED, + ...RULE_MAPPINGS_REACT_A11Y_NOT_RECOMMENDED +}; + From 6fa73c01f7acfc40355eb91b3430c5a553b1f319 Mon Sep 17 00:00:00 2001 From: Arun Tyagi Date: Wed, 14 Jan 2026 14:09:26 +0530 Subject: [PATCH 2/8] disable_react_base_config: true --- packages/code-analyzer-eslint-engine/src/config.ts | 4 ++-- .../src/rule-mappings/constants.ts | 3 +-- .../src/rule-mappings/react-jsx-a11y.ts | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/code-analyzer-eslint-engine/src/config.ts b/packages/code-analyzer-eslint-engine/src/config.ts index f3d8e293..d8af0198 100644 --- a/packages/code-analyzer-eslint-engine/src/config.ts +++ b/packages/code-analyzer-eslint-engine/src/config.ts @@ -70,7 +70,7 @@ export const DEFAULT_CONFIG: ESLintEngineConfig = { disable_lwc_base_config: false, disable_slds_base_config: false, disable_typescript_base_config: false, - disable_react_base_config: false, // Gated for now - will change to false when released + disable_react_base_config: true, // Gated for now - will change to false when released file_extensions: { javascript: ['.js', '.cjs', '.mjs', '.jsx'], typescript: ['.ts', '.tsx'], @@ -162,7 +162,7 @@ export function validateAndNormalizeConfig(configValueExtractor: ConfigValueExtr disable_typescript_base_config: eslintConfigValueExtractor.extractBooleanValue('disable_typescript_base_config'), // React support is gated - always force to true regardless of customer config // TODO: Change to eslintConfigValueExtractor.extractBooleanValue('disable_react_base_config') when released - disable_react_base_config: false, + disable_react_base_config: true, file_extensions: eslintConfigValueExtractor.extractFileExtensionsValue(), }; } diff --git a/packages/code-analyzer-eslint-engine/src/rule-mappings/constants.ts b/packages/code-analyzer-eslint-engine/src/rule-mappings/constants.ts index 249ac1a2..512facc3 100644 --- a/packages/code-analyzer-eslint-engine/src/rule-mappings/constants.ts +++ b/packages/code-analyzer-eslint-engine/src/rule-mappings/constants.ts @@ -1,5 +1,4 @@ // Convenience tag to apply to framework specific rules export const LWC = "LWC"; export const SLDS = "SLDS"; -export const REACT = "React"; -export const A11Y = "A11y"; \ No newline at end of file +export const REACT = "React"; \ No newline at end of file diff --git a/packages/code-analyzer-eslint-engine/src/rule-mappings/react-jsx-a11y.ts b/packages/code-analyzer-eslint-engine/src/rule-mappings/react-jsx-a11y.ts index 97df4d8f..2f68485e 100644 --- a/packages/code-analyzer-eslint-engine/src/rule-mappings/react-jsx-a11y.ts +++ b/packages/code-analyzer-eslint-engine/src/rule-mappings/react-jsx-a11y.ts @@ -1,5 +1,5 @@ import {COMMON_TAGS, SeverityLevel} from "@salesforce/code-analyzer-engine-api"; -import { REACT, A11Y } from './constants'; +import { REACT } from './constants'; // Recommended rules (enabled in the plugin's recommended config) export const RULE_MAPPINGS_REACT_A11Y_RECOMMENDED: Record = { From 0bd27a6795d2a93ad0e777e1b8c719dd8ce77722 Mon Sep 17 00:00:00 2001 From: Arun Tyagi Date: Wed, 14 Jan 2026 16:26:12 +0530 Subject: [PATCH 3/8] add a11y rules understanding --- .../src/rule-mappings/react-jsx-a11y.ts | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/packages/code-analyzer-eslint-engine/src/rule-mappings/react-jsx-a11y.ts b/packages/code-analyzer-eslint-engine/src/rule-mappings/react-jsx-a11y.ts index 2f68485e..d8c26eb6 100644 --- a/packages/code-analyzer-eslint-engine/src/rule-mappings/react-jsx-a11y.ts +++ b/packages/code-analyzer-eslint-engine/src/rule-mappings/react-jsx-a11y.ts @@ -3,126 +3,210 @@ import { REACT } from './constants'; // Recommended rules (enabled in the plugin's recommended config) export const RULE_MAPPINGS_REACT_A11Y_RECOMMENDED: Record = { + // Ensures images have helpful alternative text for screen readers. + // // violation + // Logo // ok "jsx-a11y/alt-text": { severity: SeverityLevel.High, tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] }, + // should contain accessible text (children or aria-label/aria-labelledby). + // // violation + // Home // ok "jsx-a11y/anchor-has-content": { severity: SeverityLevel.Moderate, tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] }, + // Valid anchors: proper href or role/button alternative. + // Click // violation + // Settings // ok "jsx-a11y/anchor-is-valid": { severity: SeverityLevel.High, tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] }, + // If using aria-activedescendant, element must have a tabindex to be focusable. + //
// violation + //
// ok "jsx-a11y/aria-activedescendant-has-tabindex": { severity: SeverityLevel.Moderate, tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] }, + // Only valid ARIA attributes are allowed. + //
// violation (misspelled) + //
// ok "jsx-a11y/aria-props": { severity: SeverityLevel.Moderate, tags: [COMMON_TAGS.RECOMMENDED, REACT, COMMON_TAGS.CATEGORIES.BEST_PRACTICES, COMMON_TAGS.LANGUAGES.JAVASCRIPT, COMMON_TAGS.LANGUAGES.TYPESCRIPT] }, + // ARIA attributes must have valid value types. + //
// violation + //