diff --git a/packages/eslint-config-airbnb/package.json b/packages/eslint-config-airbnb/package.json
index aefe9a76..769c8950 100644
--- a/packages/eslint-config-airbnb/package.json
+++ b/packages/eslint-config-airbnb/package.json
@@ -44,6 +44,7 @@
"devDependencies": {
"babel-tape-runner": "^1.3.1",
"eslint": "^2.6.0",
+ "eslint-plugin-jsx-a11y": "^0.6.0",
"eslint-plugin-react": "^4.2.3",
"react": "^0.14.8",
"tape": "^4.5.1",
@@ -51,6 +52,7 @@
},
"peerDependencies": {
"eslint": "^2.6.0",
+ "eslint-plugin-jsx-a11y": "^0.6.0",
"eslint-plugin-react": "^4.2.3"
}
}
diff --git a/packages/eslint-config-airbnb/rules/react.js b/packages/eslint-config-airbnb/rules/react.js
index 470738b7..3c05265b 100644
--- a/packages/eslint-config-airbnb/rules/react.js
+++ b/packages/eslint-config-airbnb/rules/react.js
@@ -1,5 +1,6 @@
module.exports = {
'plugins': [
+ 'jsx-a11y',
'react'
],
'ecmaFeatures': {
@@ -8,6 +9,22 @@ module.exports = {
// View link below for react rules documentation
// https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules
'rules': {
+ // Prevent use of `accessKey`
+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md
+ 'jsx-a11y/no-access-key': 2,
+
+ // Require to have a non-empty `alt` prop, or role="presentation"
+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-uses-alt.md
+ 'jsx-a11y/img-uses-alt': 2,
+
+ // Prevent img alt text from containing redundant words like "image", "picture", or "photo"
+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/redundant-alt.md
+ 'jsx-a11y/redundant-alt': 2,
+
+ // Require ARIA roles to be valid and non-abstract
+ // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/valid-aria-role.md
+ 'jsx-a11y/valid-aria-role': 2,
+
// Prevent missing displayName in a React component definition
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md
'react/display-name': [0, { 'ignoreTranspilerName': false }],
diff --git a/packages/eslint-config-airbnb/test/test-react-order.js b/packages/eslint-config-airbnb/test/test-react-order.js
index f5b2d452..81d8235f 100644
--- a/packages/eslint-config-airbnb/test/test-react-order.js
+++ b/packages/eslint-config-airbnb/test/test-react-order.js
@@ -28,9 +28,9 @@ ${body}
}
test('validate react prop order', t => {
- t.test('make sure our eslintrc has React linting dependencies', t => {
+ t.test('make sure our eslintrc has React and JSX linting dependencies', t => {
t.plan(1);
- t.equal(reactRules.plugins[0], 'react', 'uses eslint-plugin-react');
+ t.deepEqual(reactRules.plugins, ['jsx-a11y', 'react']);
});
t.test('passes a good component', t => {
diff --git a/react/README.md b/react/README.md
index 6eddabca..6db60dd1 100644
--- a/react/README.md
+++ b/react/README.md
@@ -29,7 +29,7 @@
- If you have internal state and/or refs, prefer `class extends React.Component` over `React.createClass` unless you have a very good reason to use mixins. eslint: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) [`react/prefer-stateless-function`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md)
- ```javascript
+ ```jsx
// bad
const Listing = React.createClass({
// ...
@@ -49,8 +49,7 @@
And if you don't have state or refs, prefer normal functions (not arrow functions) over classes:
- ```javascript
-
+ ```jsx
// bad
class Listing extends React.Component {
render() {
@@ -75,7 +74,7 @@
- **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`.
- **Reference Naming**: Use PascalCase for React components and camelCase for their instances. eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md)
- ```javascript
+ ```jsx
// bad
import reservationCard from './ReservationCard';
@@ -91,7 +90,7 @@
- **Component Naming**: Use the filename as the component name. For example, `ReservationCard.jsx` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.jsx` as the filename and use the directory name as the component name:
- ```javascript
+ ```jsx
// bad
import Footer from './Footer/Footer';
@@ -106,7 +105,7 @@
- Do not use `displayName` for naming components. Instead, name the component by reference.
- ```javascript
+ ```jsx
// bad
export default React.createClass({
displayName: 'ReservationCard',
@@ -122,7 +121,7 @@
- Follow these alignment styles for JSX syntax. eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md)
- ```javascript
+ ```jsx
// bad
` tags. If `alt` is an empty string, the `
` must have `role="presentation"`. eslint: [`jsx-a11y/img-uses-alt`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-uses-alt.md)
+
+ ```jsx
+ // bad
+
+
+ // bad
+
+
+ // good
+
+
+ // good
+
+ ```
+
+ - Do not use words like "image", "photo", or "picture" in `` `alt` props. eslint: [`jsx-a11y/redundant-alt`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-uses-alt.md)
+
+ > Why? Screenreaders already announce `img` elements as images, so there is no need to include this information in the alt text.
+
+ ```jsx
+ // bad
+
+
+ // good
+
+ ```
+
+ - Use only valid, non-abstract [ARIA roles](https://www.w3.org/TR/wai-aria/roles#role_definitions). eslint: [`jsx-a11y/valid-aria-role`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/valid-aria-role.md)
+
+ ```jsx
+ // bad - not an ARIA role
+