Convert Figma logo to code with AI

jsx-eslint logoeslint-plugin-jsx-a11y

Static AST checker for a11y rules on JSX elements.

3,472
635
3,472
106

Top Related Projects

25,435

Find and fix problems in your JavaScript code.

49,809

Prettier is an opinionated code formatter.

233,534

The library for web and native user interfaces.

146,335

JavaScript Style Guide

:sparkles: Monorepo for all the tooling which enables ESLint to support TypeScript

11,101

A mighty CSS linter that helps you avoid errors and enforce conventions.

Quick Overview

eslint-plugin-jsx-a11y is a static AST checker for accessibility rules on JSX elements. It helps developers identify and fix common accessibility issues in React applications, ensuring that web content is more accessible to users with disabilities.

Pros

  • Improves web accessibility without requiring extensive knowledge of WCAG guidelines
  • Integrates seamlessly with ESLint, a popular JavaScript linting tool
  • Provides customizable rules to fit specific project needs
  • Regularly updated to keep up with evolving accessibility standards

Cons

  • May produce false positives in some complex scenarios
  • Requires additional setup and configuration in projects
  • Some rules may be overly strict for certain use cases
  • Cannot catch all accessibility issues, as some require runtime testing

Code Examples

  1. Basic rule usage:
// eslint-disable-next-line jsx-a11y/alt-text
<img src="image.jpg" /> // This will trigger a warning
  1. Configuring a custom rule:
// .eslintrc.js
module.exports = {
  plugins: ['jsx-a11y'],
  rules: {
    'jsx-a11y/anchor-is-valid': ['error', {
      components: ['Link'],
      specialLink: ['to'],
    }],
  },
};
  1. Using with React:
import React from 'react';

function AccessibleButton({ onClick, children }) {
  return (
    <button onClick={onClick} aria-label="Click me">
      {children}
    </button>
  );
}

Getting Started

  1. Install the package:
npm install eslint-plugin-jsx-a11y --save-dev
  1. Add to your ESLint configuration:
// .eslintrc.js
module.exports = {
  plugins: ['jsx-a11y'],
  extends: ['plugin:jsx-a11y/recommended'],
};
  1. Run ESLint:
npx eslint .

Competitor Comparisons

25,435

Find and fix problems in your JavaScript code.

Pros of eslint

  • Broader scope, covering general JavaScript linting
  • Highly customizable with a wide range of built-in rules
  • Extensive plugin ecosystem for various frameworks and libraries

Cons of eslint

  • Requires additional configuration for React-specific linting
  • May need separate plugins for accessibility checks
  • Can be overwhelming for beginners due to its extensive options

Code Comparison

eslint:

module.exports = {
  "rules": {
    "semi": ["error", "always"],
    "quotes": ["error", "double"]
  }
}

eslint-plugin-jsx-a11y:

module.exports = {
  "plugins": ["jsx-a11y"],
  "rules": {
    "jsx-a11y/alt-text": "error",
    "jsx-a11y/aria-role": "error"
  }
}

Summary

eslint is a comprehensive JavaScript linter with a wide range of capabilities, while eslint-plugin-jsx-a11y focuses specifically on accessibility issues in JSX. eslint offers more general-purpose linting but requires additional setup for React and accessibility checks. eslint-plugin-jsx-a11y provides out-of-the-box accessibility rules for React projects but has a narrower scope. The choice between them depends on project requirements and the level of customization needed.

49,809

Prettier is an opinionated code formatter.

Pros of prettier

  • Opinionated and consistent formatting across the entire codebase
  • Supports multiple languages and file types beyond just JavaScript and JSX
  • Can be integrated into various editors and IDEs for automatic formatting on save

Cons of prettier

  • Less flexibility in customizing code style preferences
  • May conflict with existing linting rules or project-specific formatting needs
  • Does not address accessibility concerns or JSX-specific issues

Code comparison

eslint-plugin-jsx-a11y (focusing on accessibility):

<img src="image.jpg" /> // Error: img elements must have an alt prop
<div onClick={handleClick}> // Warning: Click events should use a button element

prettier (focusing on formatting):

function Example() {
  return (
    <div>
      <h1>Hello, World!</h1>
      <p>This is a formatted component.</p>
    </div>
  );
}

Summary

eslint-plugin-jsx-a11y is specifically designed for catching accessibility issues in JSX, while prettier is a code formatter that works across multiple languages. eslint-plugin-jsx-a11y provides more targeted linting for React applications, focusing on accessibility best practices. prettier, on the other hand, offers consistent code formatting but doesn't address specific coding patterns or accessibility concerns. The choice between the two depends on project needs, with many developers opting to use both tools in conjunction for comprehensive code quality and formatting.

233,534

The library for web and native user interfaces.

Pros of React

  • Comprehensive library for building user interfaces
  • Large ecosystem and community support
  • Efficient rendering with virtual DOM

Cons of React

  • Steeper learning curve for beginners
  • Requires additional tools and libraries for a complete application
  • Frequent updates may lead to compatibility issues

Code Comparison

React component:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

eslint-plugin-jsx-a11y rule:

module.exports = {
  meta: {
    docs: {
      description: 'Enforce alt text for images',
    },
  },
  create: function(context) {
    // Rule implementation
  }
};

Summary

React is a powerful library for building user interfaces, offering a comprehensive solution with a large ecosystem. However, it has a steeper learning curve and may require additional tools. eslint-plugin-jsx-a11y, on the other hand, is a focused ESLint plugin for enforcing accessibility rules in JSX. It's simpler to integrate but has a narrower scope compared to React's full UI capabilities.

React is ideal for building complex, interactive web applications, while eslint-plugin-jsx-a11y is essential for ensuring accessibility in React projects. Both tools can be used together to create robust, accessible React applications.

146,335

JavaScript Style Guide

Pros of javascript

  • Comprehensive style guide covering various aspects of JavaScript development
  • Widely adopted and recognized in the industry
  • Includes rules for ES6+ features and modern JavaScript practices

Cons of javascript

  • May be too opinionated for some developers or projects
  • Can be overwhelming due to its extensive set of rules
  • Requires additional configuration for React-specific linting

Code comparison

eslint-plugin-jsx-a11y (focused on accessibility):

// Rule: jsx-a11y/alt-text
<img src="foo.jpg" alt="Descriptive text" />

// Rule: jsx-a11y/anchor-is-valid
<a href="#" onClick={handleClick}>Click me</a>

javascript (general JavaScript style guide):

// Rule: no-var
const foo = 'bar';

// Rule: prefer-const
let x = 1;
if (x === 1) {
  x = 2;
}

Summary

eslint-plugin-jsx-a11y is specifically designed for accessibility linting in JSX, while javascript is a comprehensive JavaScript style guide. The former focuses on React and accessibility concerns, while the latter covers broader JavaScript best practices. eslint-plugin-jsx-a11y is more specialized and targeted, whereas javascript provides a wider range of rules for general JavaScript development.

:sparkles: Monorepo for all the tooling which enables ESLint to support TypeScript

Pros of typescript-eslint

  • Provides comprehensive TypeScript-specific linting rules and parser
  • Offers type-aware linting for enhanced code quality and error detection
  • Regularly updated with new features and improvements for TypeScript ecosystem

Cons of typescript-eslint

  • Larger and more complex setup compared to eslint-plugin-jsx-a11y
  • May have a steeper learning curve for developers new to TypeScript
  • Can potentially increase build times due to type checking

Code Comparison

eslint-plugin-jsx-a11y:

// eslint-disable-next-line jsx-a11y/anchor-is-valid
<a onClick={handleClick}>Click me</a>

typescript-eslint:

// @typescript-eslint/no-unused-vars
function example(unusedParam: string): void {
  // Function body
}

The eslint-plugin-jsx-a11y focuses on accessibility rules for JSX, while typescript-eslint provides TypeScript-specific linting and type checking. eslint-plugin-jsx-a11y is more specialized for React and JSX accessibility, whereas typescript-eslint offers a broader range of TypeScript-related linting capabilities.

typescript-eslint is better suited for projects using TypeScript, providing type-aware linting and a more comprehensive set of rules. However, it may require more setup and configuration. eslint-plugin-jsx-a11y is ideal for projects focusing on accessibility in React applications, with a simpler setup but a more limited scope.

11,101

A mighty CSS linter that helps you avoid errors and enforce conventions.

Pros of stylelint

  • Broader scope: Lints CSS and CSS-like syntaxes (SCSS, Less, etc.)
  • Extensive rule set: Over 170 built-in rules for comprehensive style checking
  • Plugin ecosystem: Supports custom plugins for extended functionality

Cons of stylelint

  • Limited to styling: Doesn't address accessibility concerns in JSX/React
  • Learning curve: More complex configuration due to its broader scope
  • Performance: May be slower for large projects due to extensive rule set

Code Comparison

eslint-plugin-jsx-a11y:

<img src="image.jpg" alt="Descriptive text" /> // Passes
<img src="image.jpg" /> // Fails (missing alt attribute)

stylelint:

.example {
  color: #FFF; // Passes
  colour: #FFF; // Fails (invalid property name)
}

Summary

eslint-plugin-jsx-a11y focuses on accessibility in JSX/React components, while stylelint is a more general-purpose CSS linter. eslint-plugin-jsx-a11y is essential for ensuring web accessibility in React projects, whereas stylelint helps maintain consistent and error-free CSS across various syntaxes. While both tools serve different purposes, they can be used together in a project to ensure both accessibility and styling best practices are followed.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

CI status npm version license Coverage Status Total npm downloads

Get professional support for eslint-plugin-jsx-a11y on Tidelift

eslint-plugin-jsx-a11y

Static AST checker for accessibility rules on JSX elements.

Read this in other languages.

Mexican Spanish🇲🇽

Why?

This plugin does a static evaluation of the JSX to spot accessibility issues in React apps. Because it only catches errors in static code, use it in combination with @axe-core/react to test the accessibility of the rendered DOM. Consider these tools just as one step of a larger a11y testing process and always test your apps with assistive technology.

Installation

If you are installing this plugin via eslint-config-airbnb, please follow these instructions.

You'll first need to install ESLint:

# npm
npm install eslint --save-dev

# yarn
yarn add eslint --dev

Next, install eslint-plugin-jsx-a11y:

# npm
npm install eslint-plugin-jsx-a11y --save-dev

# yarn
yarn add eslint-plugin-jsx-a11y --dev

Note: If you installed ESLint globally (using the -g flag in npm, or the global prefix in yarn) then you must also install eslint-plugin-jsx-a11y globally.

Usage - Legacy Config (.eslintrc)

Add jsx-a11y to the plugins section of your .eslintrc configuration file. You can omit the eslint-plugin- prefix:

{
  "plugins": ["jsx-a11y"]
}

Then configure the rules you want to use under the rules section.

{
  "rules": {
    "jsx-a11y/rule-name": 2
  }
}

You can also enable all the recommended or strict rules at once. Add plugin:jsx-a11y/recommended or plugin:jsx-a11y/strict in extends:

{
  "extends": ["plugin:jsx-a11y/recommended"]
}

Configurations

As you are extending our configuration, you can omit "plugins": ["jsx-a11y"] from your .eslintrc configuration file.

{
  "settings": {
    "jsx-a11y": {
      "polymorphicPropName": "as",
      "components": {
        "CityInput": "input",
        "CustomButton": "button",
        "MyButton": "button",
        "RoundButton": "button"
      },
      "attributes": {
        "for": ["htmlFor", "for"]
      }
    }
  }
}

Usage - Flat Config (eslint.config.js)

The default export of eslint-plugin-jsx-a11y is a plugin object.

const jsxA11y = require('eslint-plugin-jsx-a11y');

module.exports = [
  …
  {
    files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
    plugins: {
      'jsx-a11y': jsxA11y,
    },
    languageOptions: {
      parserOptions: {
        ecmaFeatures: {
          jsx: true,
        },
      },
    },
    rules: {
      // ... any rules you want
      'jsx-a11y/alt-text': 'error',
    },
    // ... others are omitted for brevity
  },
  …
];

Shareable Configs

There are two shareable configs, provided by the plugin.

  • flatConfigs.recommended
  • flatConfigs.strict

CJS

const jsxA11y = require('eslint-plugin-jsx-a11y');

export default [
  jsxA11y.flatConfigs.recommended,
  {
    // Your additional configs and overrides
  },
];

ESM

import jsxA11y from 'eslint-plugin-jsx-a11y';

export default [
  jsxA11y.flatConfigs.recommended,
  {
    // Your additional configs and overrides
  },
];

Note: Our shareable configs do NOT configure files or languageOptions.globals. For most of the cases, you probably want to configure some of these properties yourself.

const jsxA11y = require('eslint-plugin-jsx-a11y');
const globals = require('globals');

module.exports = [
  …
  {
    files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
    ...jsxA11y.flatConfigs.recommended,
    languageOptions: {
      ...jsxA11y.flatConfigs.recommended.languageOptions,
      globals: {
        ...globals.serviceworker,
        ...globals.browser,
      },
    },
  },
  …
];

Component Mapping

To enable your custom components to be checked as DOM elements, you can set global settings in your configuration file by mapping each custom component name to a DOM element type.

Attribute Mapping

To configure the JSX property to use for attribute checking, you can set global settings in your configuration file by mapping each DOM attribute to the JSX property you want to check. For example, you may want to allow the for attribute in addition to the htmlFor attribute for checking label associations.

Polymorphic Components

You can optionally use the polymorphicPropName setting to define the prop your code uses to create polymorphic components. This setting will be used determine the element type in rules that require semantic context.

For example, if you set the polymorphicPropName setting to as then this element:

<Box as="h3">Configurations </Box>

will be evaluated as an h3. If no polymorphicPropName is set, then the component will be evaluated as Box.

To restrict polymorphic linting to specified components, additionally set polymorphicAllowList to an array of component names.

⚠️ Polymorphic components can make code harder to maintain; please use this feature with caution.

Supported Rules

💼 Configurations enabled in.
🚫 Configurations disabled in.
☑️ Set in the recommended configuration.
🔒 Set in the strict configuration.
💡 Manually fixable by editor suggestions.
❌ Deprecated.

Name                                         Description💼🚫💡❌
accessible-emojiEnforce emojis are wrapped in <span> and provide screen reader access.❌
alt-textEnforce all elements that require alternative text have meaningful information to relay back to end user.☑️ 🔒
anchor-ambiguous-textEnforce <a> text to not exactly match "click here", "here", "link", or "a link".☑️
anchor-has-contentEnforce all anchors to contain accessible content.☑️ 🔒
anchor-is-validEnforce all anchors are valid, navigable elements.☑️ 🔒
aria-activedescendant-has-tabindexEnforce elements with aria-activedescendant are tabbable.☑️ 🔒
aria-propsEnforce all aria-* props are valid.☑️ 🔒
aria-proptypesEnforce ARIA state and property values are valid.☑️ 🔒
aria-roleEnforce that elements with ARIA roles must use a valid, non-abstract ARIA role.☑️ 🔒
aria-unsupported-elementsEnforce that elements that do not support ARIA roles, states, and properties do not have those attributes.☑️ 🔒
autocomplete-validEnforce that autocomplete attributes are used correctly.☑️ 🔒
click-events-have-key-eventsEnforce a clickable non-interactive element has at least one keyboard event listener.☑️ 🔒
control-has-associated-labelEnforce that a control (an interactive element) has a text label.☑️ 🔒
heading-has-contentEnforce heading (h1, h2, etc) elements contain accessible content.☑️ 🔒
html-has-langEnforce <html> element has lang prop.☑️ 🔒
iframe-has-titleEnforce iframe elements have a title attribute.☑️ 🔒
img-redundant-altEnforce <img> alt prop does not contain the word "image", "picture", or "photo".☑️ 🔒
interactive-supports-focusEnforce that elements with interactive handlers like onClick must be focusable.☑️ 🔒💡
label-has-associated-controlEnforce that a label tag has a text label and an associated control.☑️ 🔒
label-has-forEnforce that <label> elements have the htmlFor prop.☑️ 🔒❌
langEnforce lang attribute has a valid value.
media-has-captionEnforces that <audio> and <video> elements must have a <track> for captions.☑️ 🔒
mouse-events-have-key-eventsEnforce that onMouseOver/onMouseOut are accompanied by onFocus/onBlur for keyboard-only users.☑️ 🔒
no-access-keyEnforce that the accessKey prop is not used on any element to avoid complications with keyboard commands used by a screen reader.☑️ 🔒
no-aria-hidden-on-focusableDisallow aria-hidden="true" from being set on focusable elements.
no-autofocusEnforce autoFocus prop is not enabled.☑️ 🔒
no-distracting-elementsEnforce distracting elements are not used.☑️ 🔒
no-interactive-element-to-noninteractive-roleInteractive elements should not be assigned non-interactive roles.☑️ 🔒
no-noninteractive-element-interactionsNon-interactive elements should not be assigned mouse or keyboard event listeners.☑️ 🔒
no-noninteractive-element-to-interactive-roleNon-interactive elements should not be assigned interactive roles.☑️ 🔒
no-noninteractive-tabindextabIndex should only be declared on interactive elements.☑️ 🔒
no-onchangeEnforce usage of onBlur over onChange on select menus for accessibility.❌
no-redundant-rolesEnforce explicit role property is not the same as implicit/default role property on element.☑️ 🔒
no-static-element-interactionsEnforce that non-interactive, visible elements (such as <div>) that have click handlers use the role attribute.☑️ 🔒
prefer-tag-over-roleEnforces using semantic DOM elements over the ARIA role property.
role-has-required-aria-propsEnforce that elements with ARIA roles must have all required attributes for that role.☑️ 🔒
role-supports-aria-propsEnforce that elements with explicit or implicit roles defined contain only aria-* properties supported by that role.☑️ 🔒
scopeEnforce scope prop is only used on <th> elements.☑️ 🔒
tabindex-no-positiveEnforce tabIndex value is not greater than zero.☑️ 🔒

The following rules have extra options when in recommended mode:

no-interactive-element-to-noninteractive-role

'jsx-a11y/no-interactive-element-to-noninteractive-role': [
  'error',
  {
    tr: ['none', 'presentation'],
  },
]

no-noninteractive-element-interactions

'jsx-a11y/no-noninteractive-element-interactions': [
  'error',
  {
    handlers: [
      'onClick',
      'onMouseDown',
      'onMouseUp',
      'onKeyPress',
      'onKeyDown',
      'onKeyUp',
    ],
  },
]

no-noninteractive-element-to-interactive-role

'jsx-a11y/no-noninteractive-element-to-interactive-role': [
  'error',
  {
    ul: [
      'listbox',
      'menu',
      'menubar',
      'radiogroup',
      'tablist',
      'tree',
      'treegrid',
    ],
    ol: [
      'listbox',
      'menu',
      'menubar',
      'radiogroup',
      'tablist',
      'tree',
      'treegrid',
    ],
    li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
    table: ['grid'],
    td: ['gridcell'],
  },
]

no-noninteractive-tabindex

'jsx-a11y/no-noninteractive-tabindex': [
  'error',
  {
    tags: [],
    roles: ['tabpanel'],
  },
]

no-static-element-interactions

'jsx-a11y/no-noninteractive-element-interactions': [
  'error',
  {
    handlers: [
      'onClick',
      'onMouseDown',
      'onMouseUp',
      'onKeyPress',
      'onKeyDown',
      'onKeyUp',
    ],
  },
]

Creating a new rule

If you are developing new rules for this project, you can use the create-rule script to scaffold the new files.

./scripts/create-rule.js my-new-rule

Some background on WAI-ARIA, the AX Tree and Browsers

Accessibility API

An operating system will provide an accessibility API that maps application state and content onto input/output controllers such as a screen reader, braille device, keyboard, etc.

These APIs were developed as computer interfaces shifted from buffers (which are text-based and inherently quite accessible) to graphical user interfaces (GUIs). The first attempts to make GUIs accessible involved raster image parsing to recognize characters, words, etc. This information was stored in a parallel buffer and made accessible to assistive technology (AT) devices.

As GUIs became more complex, the raster parsing approach became untenable. Accessibility APIs were developed to replace them. Check out NSAccessibility (AXAPI) for an example. See Core Accessibility API Mappings 1.1 for more details.

Browsers

Browsers support an Accessibility API on a per operating system basis. For instance, Firefox implements the MSAA accessibility API on Windows, but does not implement the AXAPI on OSX.

The Accessibility (AX) Tree & DOM

From the W3 Core Accessibility API Mappings 1.1

The accessibility tree and the DOM tree are parallel structures. Roughly speaking the accessibility tree is a subset of the DOM tree. It includes the user interface objects of the user agent and the objects of the document. Accessible objects are created in the accessibility tree for every DOM element that should be exposed to assistive technology, either because it may fire an accessibility event or because it has a property, relationship or feature which needs to be exposed. Generally, if something can be trimmed out it will be, for reasons of performance and simplicity. For example, a <span> with just a style change and no semantics may not get its own accessible object, but the style change will be exposed by other means.

Browser vendors are beginning to expose the AX Tree through inspection tools. Chrome has an experiment available to enable their inspection tool.

You can also see a text-based version of the AX Tree in Chrome in the stable release version.

Viewing the AX Tree in Chrome

  1. Navigate to chrome://accessibility/ in Chrome.
  2. Toggle the accessibility off link for any tab that you want to inspect.
  3. A link labeled show accessibility tree will appear; click this link.
  4. Balk at the wall of text that gets displayed, but then regain your conviction.
  5. Use the browser's find command to locate strings and values in the wall of text.

Pulling it all together

A browser constructs an AX Tree as a subset of the DOM. ARIA heavily informs the properties of this AX Tree. This AX Tree is exposed to the system level Accessibility API which mediates assistive technology agents.

We model ARIA in the aria-query project. We model AXObjects (that comprise the AX Tree) in the axobject-query project. The goal of the WAI-ARIA specification is to be a complete declarative interface to the AXObject model. The in-draft 1.2 version is moving towards this goal. But until then, we must consider the semantics constructs afforded by ARIA as well as those afforded by the AXObject model (AXAPI) in order to determine how HTML can be used to express user interface affordances to assistive technology users.

License

eslint-plugin-jsx-a11y is licensed under the MIT License.

NPM DownloadsLast 30 Days