logoESLint React

Migrating from eslint-plugin-react

Complete guide for migrating from eslint-plugin-react to ESLint React

This page is a work in progress and may be incomplete.

This guide provides a comprehensive comparison between eslint-plugin-react and ESLint React rules to help you migrate your existing configuration.

Overview

ESLint React is designed as a modern replacement for eslint-plugin-react with improved performance, better TypeScript support, and more accurate rule implementations. However, not all rules have direct equivalents, and some behave differently.

Rule Comparison Table

Legend

  • 🔧 Fully supported - Rule is supported, and has an auto-fix
  • Mostly supported - Rule is supported but doesn't have an auto-fix
  • 🟡 Partial support - Similar but not identical functionality
  • Not supported - No equivalent rule
  • ➡️ External plugin - Rule is available in another ESLint plugin
  • 🚫 Legacy - Rule is not applicable in modern React development (e.g. class-based components, propTypes)
  • ⚠️ Warning - Rule has been deprecated in eslint-plugin-react

A variety of rules are marked legacy, but still have equivalent rules. This distinction was done to more accurately assess migration for React written with function components and no longer use propTypes.

Table

The following table compares all rules from eslint-plugin-react with their ESLint React (or external) equivalents:

eslint-plugin-react Rule NameNew Rule NamePrev StatusStatus
boolean-prop-naming
button-has-typedom/no-missing-button-type🔧
checked-requires-onchange-or-readonly
default-props-match-prop-typesno-prop-types🚫
destructuring-assignmentprefer-destructuring-assignment🔧
display-nameno-missing-component-display-name
forbid-component-props
forbid-dom-props
forbid-elementsno-prop-types
forbid-foreign-prop-types🚫
forbid-prop-typesno-prop-types🚫
forward-ref-uses-refno-useless-forward-ref🟡
function-component-definition🔧
hook-use-statenaming-convention/use-state
iframe-missing-sandboxdom/no-missing-iframe-sandbox🔧
jsx-boolean-valuejsx-shorthand-boolean / avoid-shorthand-boolean🔧
jsx-child-element-spacing@stylistic/jsx-child-element-spacing➡️
jsx-closing-bracket-location@stylistic/jsx-closing-bracket-location🔧➡️
jsx-closing-tag-location@stylistic/jsx-closing-tag-location🔧➡️
jsx-curly-brace-presence@stylistic/jsx-curly-brace-presence🔧➡️
jsx-curly-newline@stylistic/jsx-curly-newline🔧➡️
jsx-curly-spacing@stylistic/jsx-curly-spacing🔧➡️
jsx-equals-spacing@stylistic/jsx-equals-spacing🔧➡️
jsx-filename-extensionnaming-convention/filename-extension
jsx-first-prop-new-line@stylistic/jsx-first-prop-new-line🔧➡️
jsx-fragmentsjsx-shorthand-fragment / avoid-shorthand-fragment🔧
jsx-handler-names
jsx-indent@stylistic/jsx-indent🔧➡️
jsx-indent-props@stylistic/jsx-indent-props🔧➡️
jsx-keyno-missing-key
jsx-max-depth
jsx-max-props-per-line@stylistic/jsx-max-props-per-line🔧➡️
jsx-newline@stylistic/jsx-newline🔧➡️
jsx-no-bind
jsx-no-comment-textnodesjsx-no-comment-textnodes / no-comment-textnodes
jsx-no-constructed-context-valuesno-unstable-context-value
jsx-no-duplicate-propsjsx-no-duplicate-props
jsx-no-leaked-renderno-leaked-conditional-rendering🔧
jsx-no-literals
jsx-no-script-urldom/no-script-url
jsx-no-target-blankdom/no-unsafe-target-blank🔧
jsx-no-undefjsx-no-undef
jsx-no-useless-fragmentno-useless-fragment🔧
jsx-one-expression-per-line@stylistic/jsx-one-expression-per-line🔧➡️
jsx-pascal-casenaming-convention/component-name
jsx-props-no-multi-spaces@stylistic/jsx-props-no-multi-spaces🔧➡️
jsx-props-no-spread-multi
jsx-props-no-spreading
jsx-sort-default-props⚠️
jsx-sort-props@stylistic/jsx-sort-props🔧➡️
jsx-space-before-closing⚠️
jsx-tag-spacing@stylistic/jsx-tag-spacing🔧➡️
jsx-uses-reactjsx-uses-react
jsx-uses-varsjsx-uses-vars
jsx-wrap-multilines@stylistic/jsx-wrap-multilines🔧➡️
no-access-state-in-setstateno-access-state-in-setstate
no-adjacent-inline-elements
no-array-index-keyno-array-index-key
no-arrow-function-lifecycle🔧🚫
no-children-propno-children-prop
no-dangerdom/no-dangerously-set-innerhtml
no-danger-with-childrendom/no-dangerously-set-innerhtml-with-children
no-deprecatedno-component-will-mount + no-component-will-receive-props + no-component-will-update + no-create-ref + no-forward-ref🟡
no-did-mount-set-stateno-set-state-in-component-did-mount🚫
no-did-update-set-stateno-set-state-in-component-did-update🚫
no-direct-mutation-stateno-direct-mutation-state🚫
no-find-dom-nodedom/no-find-dom-node
no-invalid-html-attribute
no-is-mounted🚫
no-multi-comp
no-namespacedom/no-namespace
no-object-type-as-default-propno-unstable-default-props
no-redundant-should-component-updateno-redundant-should-component-update🚫
no-render-return-valuedom/no-render-return-value
no-set-state🚫
no-string-refsno-string-refs
no-this-in-sfc
no-typos
no-unescaped-entities
no-unknown-propertydom/no-unknown-property🔧
no-unsafeno-unsafe-component-will-mount + no-unsafe-component-will-receive-props + no-unsafe-component-will-update🟡
no-unstable-nested-componentsno-nested-component-definitions
no-unused-class-component-methodsno-unused-class-component-members🚫
no-unused-prop-typesno-prop-types🚫
no-unused-stateno-unused-state🚫
no-will-update-set-stateno-set-state-in-component-will-update
prefer-es6-classno-prop-types🚫
prefer-exact-propsno-prop-types🚫
prefer-read-only-propsprefer-read-only-props🔧🚫
prefer-stateless-function🚫
prop-typesno-prop-types🚫
react-in-jsx-scope🚫
require-default-propsno-prop-types🚫
require-optimization🚫
require-render-return🚫
self-closing-comp@stylistic/jsx-self-closing-comp🔧➡️
sort-comp🚫
sort-default-propsno-prop-types🚫
sort-prop-typesno-prop-types🔧🚫
state-in-constructor🚫
static-property-placement🚫
style-prop-object
void-dom-elements-no-childrendom/no-void-elements-with-children

ESLint React Column

  • Rule names link to ESLint React documentation
  • Multiple rules separated by / indicate alternative approaches
  • Rules with + indicate multiple rules that together provide equivalent functionality

Gradual Migration

You can migrate gradually by using both plugins together, using the disableConflictEslintPluginReact ruleset:

import reactPlugin from "eslint-plugin-react";
import eslintReact from "@eslint-react/eslint-plugin";
export default [
  // Start with the eslint-plugin-react
  {
    files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
    // Whatever config you had enabled with eslint-plugin-react
    ...reactPlugin.configs.flat.recommended,

    // Now disable all conflicting rules
    ...eslintReact.configs['disable-conflict-eslint-plugin-react],

    // Now enable the desired rules
    ...eslintReact.configs.recommended,
  }
];