Skip to content

react

npm version License: MIT Node.js ESLint React

> ESLint flat config for React with TypeScript. Extends @jmlweb/eslint-config-base with React, Hooks and JSX rules.

> 🔧 Maintenance mode: only dependency and security updates, no new rules. For new projects use @jmlweb/oxlint-config-react. To move an existing project, see the migration guide.

  • ⚛️ React rules: @eslint-react recommended-typescript preset
  • 🪝 Hooks and React Compiler rules: official eslint-plugin-react-hooks recommended preset, applied to every file
  • 🧩 JSX style: PascalCase, self-closing, no needless braces or fragments, sorted props
  • 🔒 Strict TypeScript: everything from @jmlweb/eslint-config-base
  • 🎨 Prettier compatible: disables rules that conflict with Prettier
Terminal window
npm install --save-dev @jmlweb/eslint-config-react @jmlweb/eslint-config-base eslint @eslint/js typescript-eslint eslint-config-prettier eslint-plugin-simple-import-sort @eslint-react/eslint-plugin @stylistic/eslint-plugin eslint-plugin-perfectionist eslint-plugin-react-hooks

> 💡 Upgrading? See the Migration Guide.

eslint.config.js
import reactConfig from '@jmlweb/eslint-config-react';
export default [
...reactConfig,
// Project-specific overrides
];
eslint.config.js
import reactConfig from '@jmlweb/eslint-config-react';
export default [
...reactConfig,
{
files: ['**/*.test.tsx', '**/*.spec.tsx'],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@eslint-react/no-array-index-key': 'off',
},
},
{
ignores: ['dist/', 'build/', 'node_modules/'],
},
];
eslint.config.js
import reactConfig from '@jmlweb/eslint-config-react';
export default [
...reactConfig,
{
settings: {
'react-x': {
version: '19.2', // default: 'detect'
},
},
},
];
eslint.config.js
import reactConfig from '@jmlweb/eslint-config-react';
export default [
...reactConfig,
{
rules: {
'react-hooks/set-state-in-effect': 'warn',
},
},
];
Rules Applied to
@eslint-react preset, react-hooks preset all files (hooks in .ts)
JSX style, import sorting, PascalCase function names **/*.tsx, **/*.jsx

Hooks rules come from eslint-plugin-react-hooks. @eslint-react’s ports of the same rules are turned off, so each problem is reported once as react-hooks/*.

Rule Level Description
react-hooks/rules-of-hooks error Rules of Hooks
react-hooks/exhaustive-deps warn Hook dependencies
react-hooks/purity, refs, immutability, … error React Compiler rules
@eslint-react/no-missing-key error Missing keys in lists
@eslint-react/no-array-index-key warn Array index as key
@eslint-react/jsx-no-children-prop error children passed as a prop
@eslint-react/jsx-no-useless-fragment error Unnecessary fragments
@eslint-react/dom-no-unknown-property error Unknown DOM properties (class, …)
@eslint-react/dom-no-unsafe-target-blank error target="_blank" without rel
@stylistic/jsx-pascal-case error PascalCase component names
@stylistic/jsx-self-closing-comp error Self-close elements without children
@stylistic/jsx-curly-brace-presence error No unnecessary curly braces
perfectionist/sort-jsx-props error Reserved, shorthand, regular, then callbacks

The naming convention is relaxed so functions may be PascalCase (components). The React version is auto-detected.

Imports are sorted and type-only imports are enforced.

Before:

import { Component } from './component';
import React, { useState } from 'react';
import { User } from './types';

After eslint --fix:

import React, { useState } from 'react';
import { type User } from './types';
import { Component } from './component';
  • ✅ React libraries and apps written in TypeScript
  • ✅ Strict Hooks and React Compiler checks, even without the Compiler
  • ✅ Consistent JSX style across a team

For non-React TypeScript use @jmlweb/eslint-config-base. For new projects prefer @jmlweb/oxlint-config-react.

Spread the config, then add objects after it. Later entries win.

eslint.config.js
import reactConfig from '@jmlweb/eslint-config-react';
export default [
...reactConfig,
{
files: ['**/*.tsx'],
rules: {
'@stylistic/jsx-curly-brace-presence': 'off',
},
},
];
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix"
}
}
Terminal window
npm run lint
  • Node.js >= 22.12.0
  • ESLint ^9.0.0 || ^10.0.0 (flat config)
  • React >= 17 (modern JSX transform)
  • TypeScript project with a tsconfig.json (versions supported by typescript-eslint 8)
  • eslint (^9.0.0 || ^10.0.0)
  • @eslint/js (^9.0.0 || ^10.0.0)
  • typescript-eslint (^8.0.0)
  • eslint-config-prettier (^9.1.0 || ^10.0.0)
  • eslint-plugin-simple-import-sort (^12.0.0 || ^13.0.0 || ^14.0.0)
  • @eslint-react/eslint-plugin (^5.0.0)
  • @stylistic/eslint-plugin (^5.0.0)
  • eslint-plugin-perfectionist (^5.0.0)
  • eslint-plugin-react-hooks (^7.0.0)
  • @jmlweb/eslint-config-base (^3.0.3)

Hooks rules now come from eslint-plugin-react-hooks’ recommended preset instead of two hand-picked rules.

  • React Compiler rules are enabled, most as errors (purity, refs, immutability, set-state-in-effect, static-components, …)
  • Hooks rules also apply to .ts files
  1. Run npx eslint . and fix the new reports.
  2. To adopt gradually, lower rules to warn, for example 'react-hooks/set-state-in-effect': 'warn'.

eslint-plugin-react is replaced by @eslint-react/eslint-plugin, which supports ESLint 10.

  • Remove eslint-plugin-react; add @eslint-react/eslint-plugin, @stylistic/eslint-plugin and eslint-plugin-perfectionist
  • react/* rules are now @eslint-react/*, @stylistic/* or perfectionist/sort-jsx-props
  • jsx-boolean-value, jsx-fragments and no-unescaped-entities are no longer enforced
  • settings.react.version is now settings['react-x'].version
  1. Swap the dependencies:

    Terminal window
    npm uninstall eslint-plugin-react
    npm install --save-dev @eslint-react/eslint-plugin @stylistic/eslint-plugin eslint-plugin-perfectionist
  2. Rename react/* rules in overrides and eslint-disable comments. Most keep their name under @eslint-react/ (react/no-array-index-key becomes @eslint-react/no-array-index-key). These change name:

    4.x 5.0
    react/jsx-key @eslint-react/no-missing-key
    react/no-children-prop @eslint-react/jsx-no-children-prop
    react/no-danger-with-children @eslint-react/dom-no-dangerously-set-innerhtml-with-children
    react/no-find-dom-node @eslint-react/dom-no-find-dom-node
    react/no-render-return-value @eslint-react/dom-no-render-return-value
    react/no-unknown-property @eslint-react/dom-no-unknown-property
    react/no-deprecated @eslint-react/no-component-will-*, @eslint-react/dom-no-render, and similar
    react/display-name (off) @eslint-react/no-missing-component-display-name (off)
    react/jsx-pascal-case @stylistic/jsx-pascal-case
    react/self-closing-comp @stylistic/jsx-self-closing-comp
    react/jsx-curly-brace-presence @stylistic/jsx-curly-brace-presence
    react/jsx-sort-props perfectionist/sort-jsx-props
  3. Run npx eslint --fix . and review the remaining reports.

Node.js >= 22.12.0 is now required (see the Changelog).

MIT