Skip to main content
The React rule file adds linting for JSX syntax, React component patterns, and prop validation using eslint-plugin-react. These rules are only active when you extend eslint-config-airbnb (not eslint-config-airbnb-base). Source: eslint-config-airbnb/rules/react
The React rules file also adjusts two base rules for React compatibility: no-underscore-dangle is extended to allow __REDUX_DEVTOOLS_EXTENSION_COMPOSE__, and class-methods-use-this is configured to exempt all React lifecycle methods.

JSX formatting

Severity: errorJSX attribute values must use double quotes, unlike JavaScript strings which use single quotes.
// Bad
<Component className='foo' />

// Good
<Component className="foo" />
Severity: error (2 spaces)JSX elements must be indented with 2 spaces, consistent with the base style rules.
Severity: error (2 spaces)Props on a multiline JSX element must be indented 2 spaces from the opening tag.
// Good
<Component
  foo="bar"
  baz="qux"
/>
Severity: error (line-aligned)The closing /> or > of a multiline JSX element must align with the line that contains the opening tag.
// Good
<Component
  foo="bar"
/>
Severity: errorThe closing tag of a multiline JSX element must be on its own line and aligned with the opening tag.
Severity: error (never)
// Bad
<Component foo={ bar } />

// Good
<Component foo={bar} />
Severity: error (never)
// Bad
<Component foo = {bar} />

// Good
<Component foo={bar} />
Severity: errorRules:
  • No space before the closing slash of self-closing elements
  • Space before closing /> of self-closing elements
  • No space after the opening <
  • No space before the closing >
// Good
<Component />
<Component></Component>
Severity: errorJSX that spans multiple lines must be wrapped in parentheses in: declarations, assignments, return statements, arrow function bodies, conditionals, logical expressions, and props.
// Good
const element = (
  <div>
    <span>Hello</span>
  </div>
);
Severity: error (multiline-multiprop)When a JSX element has multiple props and spans multiple lines, the first prop must be on a new line.
Severity: error (max: 1 when multiline)Multiline JSX elements must have at most one prop per line.
Severity: error (allow single child)Each JSX expression must be on its own line. Single-child elements are exempt.
Severity: error (never for props and children)Do not use curly braces around string literals in props or children when they are not needed.
// Bad
<Component foo={'bar'}>{'Hello'}</Component>

// Good
<Component foo="bar">Hello</Component>

Component structure

Severity: error (ignorePureComponents: true)Class components that do not use state, lifecycle methods, or refs should be written as function components. Pure components (React.PureComponent) are exempt.
Severity: errorWhen a class component is needed, it must use the ES6 class syntax rather than React.createClass.
Severity: errorNamed function components must use function declarations or function expressions. Unnamed components must use function expressions.
// Good
function MyComponent({ name }) {
  return <div>{name}</div>;
}
Severity: errorClass component methods must appear in this order:
  1. Static variables
  2. Static methods
  3. Instance variables
  4. Lifecycle methods
  5. Event handlers (handle*, on*)
  6. Getters and setters
  7. Other instance methods
  8. Render helpers (render*)
  9. render
Severity: errorComponent state must be initialized in the constructor, not as a class field.
Severity: errorStatic component properties (defaultProps, propTypes, displayName) must be declared as property assignments after the class definition, not as static class fields.
Severity: error (always)Props and state must always be destructured before use.
// Bad
function MyComponent(props) {
  return <div>{props.name}</div>;
}

// Good
function MyComponent({ name }) {
  return <div>{name}</div>;
}

Props and prop types

Severity: errorEvery prop used in a component must be declared in propTypes. This catches typos and documents component contracts.
Severity: errorProps that are not marked as required in propTypes must have a corresponding entry in defaultProps.
Severity: errorEvery entry in defaultProps must correspond to a non-required prop in propTypes.
Severity: errorThe following vague prop types are forbidden: any, array, object. Use more specific shapes instead.
// Bad
MyComponent.propTypes = {
  data: PropTypes.object,
};

// Good
MyComponent.propTypes = {
  data: PropTypes.shape({
    id: PropTypes.number.isRequired,
    name: PropTypes.string.isRequired,
  }),
};
Severity: errorProp types that are declared but never referenced in the component are removed.
Severity: errorSpreading props onto HTML elements and custom components is disallowed. Explicit spread via explicitSpread: 'ignore' allows controlled spreading.
// Bad
<Component {...props} />

// You must pass props explicitly
<Component foo={props.foo} bar={props.bar} />
Severity: errorComponents should define exact prop shapes so that extra props are caught at lint time.

Safety and correctness

Severity: errorFlags use of lifecycle methods and APIs that React has deprecated, such as componentWillMount and findDOMNode.
Severity: warnUsing dangerouslySetInnerHTML creates XSS risk. The rule warns rather than errors to allow intentional usage, but every use should be carefully reviewed.
Severity: errorA React element cannot have both children and dangerouslySetInnerHTML — React will throw at runtime.
Severity: errorUsing the array index as a React key causes incorrect reconciliation when the list is reordered or items are inserted. Use a stable, unique identifier instead.
// Bad
items.map((item, index) => <Item key={index} {...item} />)

// Good
items.map((item) => <Item key={item.id} {...item} />)
Severity: errorDefining a component inside another component’s render function creates a new component type on every render, forcing full unmount/remount.
Severity: errorReading this.state inside setState is unreliable because state updates are batched. Use the functional form of setState instead.
// Bad
this.setState({ count: this.state.count + 1 });

// Good
this.setState((prevState) => ({ count: prevState.count + 1 }));
Severity: errorString refs (ref="myRef") are a legacy API. Use React.createRef() or the useRef hook instead.
Severity: errorAttributes like href="javascript:void(0)" execute code and are an XSS vector. Also applied to the to prop of Link components.
Severity: errorCharacters like ", ', {, and > must be escaped in JSX text content to avoid parser ambiguity.
Severity: errorPassing a newly created object or array literal as a context value causes all consumers to re-render on every render cycle. Extract the value to a stable variable.
Severity: errorState properties that are defined but never read are removed.
Severity: errorReact.PureComponent already performs shallow prop and state comparison. Adding shouldComponentUpdate overrides this behavior and is redundant (or a misuse of PureComponent).

JSX file conventions

Severity: errorJSX syntax is only allowed in .jsx files. This makes it easy to identify React components by file extension.
If your project uses TypeScript, override this rule to also allow .tsx files: "react/jsx-filename-extension": ["error", { "extensions": [".jsx", ".tsx"] }]
Severity: errorUser-defined JSX components must start with a capital letter. All-caps names (e.g., SVG) are allowed.
Severity: error
// Bad
<Component></Component>

// Good
<Component />
Severity: error (syntax)
// Bad
<React.Fragment><Child /></React.Fragment>

// Good
<><Child /></>
Severity: errorA fragment that wraps only a single child is unnecessary.
// Bad
<><Child /></>

// Good
<Child />

Build docs developers (and LLMs) love