What's Changed
This release consolidates all changes since v3.0.0.
💥 Breaking Changes
New eslint-plugin-react-jsx package
A new dedicated plugin for React Flavored JSX rules has been introduced. Several rules have been migrated from eslint-plugin-react-x and eslint-plugin-react-dom to this new package:
Old Rule (react-x/)
| New Rule (react-jsx/)
| Change |
|---|---|---|
jsx-key-before-spread
| no-key-after-spread
| relocated, renamed |
jsx-no-comment-textnodes
| no-comment-textnodes
| relocated, renamed |
no-children-prop
| no-children-prop
| relocated |
no-useless-fragment
| no-useless-fragment
| relocated |
Old Rule (react-dom/)
| New Rule (react-jsx/)
| Change |
|---|---|---|
no-namespace
| no-namespace
| relocated |
Rule prefix changes in @eslint-react/eslint-plugin
Rules from individual plugins now use a flattened naming convention when accessed through the unified @eslint-react/eslint-plugin package:
@eslint-react/<rule>->@eslint-react/<rule>(no changes)@eslint-react-jsx-<rule>->@eslint-react-jsx-<rule>(no changes)@eslint-react/rsc/<rule>->@eslint-react/rsc-<rule>@eslint-react/dom/<rule>->@eslint-react/dom-<rule>@eslint-react/web-api/<rule>->@eslint-react/web-api-<rule>@eslint-react/naming-convention/<rule>->@eslint-react/naming-convention-<rule>@eslint-react/debug/<rule>->@eslint-react/debug-<rule>
Removed Rules from eslint-plugin-react-x
The following rules have been removed from eslint-plugin-react-x:
| Rule | Replaced by |
|---|---|
react-x/jsx-dollar
| @eslint-react/kit (custom rule)
|
react-x/jsx-shorthand-boolean
| @eslint-react/kit (custom rule)
|
react-x/jsx-shorthand-fragment
| @eslint-react/kit (custom rule)
|
react-x/unstable-rules-of-props
| Recipes: custom-rules-of-props |
react-x/unstable-rules-of-state
| Recipes: custom-rules-of-state |
JSX utilities extracted from @eslint-react/core to @eslint-react/jsx
The JSX module has been extracted from @eslint-react/core into a new standalone @eslint-react/jsx package. The following exports are no longer available from @eslint-react/core:
JsxInspectorclass — removed, replaced with standalone utility functions from@eslint-react/jsx(e.g.findAttribute,hasAttribute,getChildren,isElement,isFragmentElement,isHostElement,isJsxLike, etc.)JsxConfig,JsxDetectionHint,JsxAttributeValue— moved to@eslint-react/jsxgetElementType— renamed togetElementFullTypein@eslint-react/jsxgetElementSelfName— renamed togetElementSelfTypein@eslint-react/jsx
Removed ref APIs from @eslint-react/core
The following ref-related APIs have been removed from @eslint-react/core without replacement:
isRefIdisInitializedFromRefgetRefInitisRefLikeName
Core collector API renames
The collector APIs in @eslint-react/core have been renamed:
| Before | After |
|---|---|
useComponentCollector()
| getComponentCollector()
|
useComponentCollectorLegacy()
| getComponentCollectorLegacy()
|
useHookCollector()
| getHookCollector()
|
Collector return property .ctx
| Collector return property .api
|
@eslint-react/kit API restructuring
The hint API in @eslint-react/kit has been restructured for better namespacing:
| Before | After |
|---|---|
hint.defaultComponent
| hint.component.Default
|
@eslint-react/kit API redesign
The defineConfig function has been replaced with a chainable builder API for better composability and type inference:
| Before | After |
|---|---|
defineConfig({ rules: [rule1, rule2] })
| eslintReactKit().use(rule1).use(rule2).getConfig()
|
The new API provides better TypeScript intellisense and allows for more flexible rule configuration:
import eslintReactKit from "@eslint-react/kit";
export default defineConfig(
{
files: ["**/*.{ts,tsx}"],
extends: [
// ... other configs
eslintReactKit()
.use(functionComponentDefinition)
.use(maxComponentPerFile, { max: 1 })
.getConfig(),
],
},
);react-jsx: Renameno-deoptimizationrule tono-key-after-spreadfor clearer intent (#1668).kit: Removefilesoption fromgetConfig()and normalize file extensions handling (#1669). Thefilesoption is no longer supported; file extensions are now automatically normalized to include both standard and TypeScript variants.
✨ New
- New
jsxanddisable-jsxconfig presets in@eslint-react/eslint-plugin. - New
react-dom-with-custom-rulesexample project demonstrating custom rule creation with@eslint-react/kit. eslint-plugin-react-jsx: New plugin dedicated to React Flavored JSX rules. Ships withrecommendedandstrictconfig presets.react-jsx/no-children-prop-with-children: New rule that disallows passingchildrenas a prop when children are also passed as nested content.react-jsx/no-key-after-spread: New rule that prevents patterns causing deoptimization when using the automatic JSX runtime (e.g. placingkeyafter spread props).react-jsx/no-namespace: New rule that disallows JSX namespace syntax, as React does not support them.@eslint-react/jsx: New utility package for static analysis of JSX patterns in TSESTree ASTs, extracted from@eslint-react/core.@eslint-react/kit: New utility module for building custom ESLint rules with React awareness. Provides a chainableeslintReactKit().use().getConfig()builder API and aRuleToolkitinterface with pre-bound context helpers for component/hook analysis.@eslint-react/kit: Re-export types from@eslint-react/sharedfor better TypeScript intellisense.kit: AddgetPlugin()API toBuilderfor fine-grained control over plugin namespace and rule severities.kit: Support more file extensions ingetConfigdefaults (js,mjs,cjs,jsx,ts,mts,cts,tsx), closes #1659.kit.settings: Expose normalized ESLint React settings viasettingsproperty onRuleToolkit.docs(utilities): Add utilities documentation for utility modules, closes #1656.
🐞 Fixes
purity: Remove console methods from impurity detection, closes #1616 (#1676).purity: Treatnew Date(arg)as pure, closes #1582 (#1677).react-jsx: Improve type safety and edge case handling for JSX rules (#1664).react-x:component-hook-factories: Exclude HOC patterns and test mocks from component detection, closes #1652. Thanks @zerone0x!react-x:component-hook-factories: UseisComponentNameLoosefor more accurate component parameter checks.react-x:immutability: Exclude event handler params from props mutation check, closes #1647. Thanks @zerone0x!react-x:no-duplicate-key: Fix false positive for SVGxlinkattributes.react-x:purity: RemoveAbortControllerfrom impure constructors, closes #1648. Thanks @zerone0x!core:isReactAPI: Fix API name matching logic to useendsWithfor precise matching.core:isRenderMethodLike: SupportClassExpressionin addition toClassDeclaration.core:findImportSource: Add cycle detection to prevent infinite recursion when resolving variable aliases.ast: Fix JSX attribute name comparison to useisNodeEqualinstead of string comparison, properly handlingJSXNamespacedName(e.g.,xlink:href).ast: UpdateFunctionInitPathtypes to support method definitions and property arrow functions in class expressions.ast:isNodeEqual: FixJSXNamespacedNamecomparison logic.var: Fix logic bugs incompute-object-type,find-enclosing-assignment-target, andis-value-equalutilities (#1672).docs: Update package structure documentation in contributing guide and FAQ, closes #1658.
🪄 Improvements
react-jsx/no-children-prop: Add suggestion-fix feature to move children from prop to element content.@eslint-react/eslint-plugin: Unified plugin architecture refactored — configs now auto-inject the plugin, so users no longer need to manually register it separately.refactor(kit): ImproveBuilderandRuleDefinitionimplementation for better type inference and code organization.refactor(kit): ReplacedefineConfigwith chainable.use().getConfig()builder API, closes #1644.refactor(kit): Remove unused type parameter fromCollectorWithContext<T, E>toCollectorWithContext<T>.refactor(kit): Rename parameterargstooptions.refactor(eff): ReplacegetOrElse/getOrElseUpdatewithgetOrInsert/getOrInsertComputedfor better API consistency, closes #1657.docs(kit): Add comprehensive documentation forgetConfig()andgetPlugin()APIs with usage examples.docs(kit): Replace "max-component-per-file" example with "destructure-component-props" example for better practical guidance.docs(website): Improveconfigure-project-rulesdocumentation with clearer examples and explanations.docs: add recipes section; remove unstable-rules-of-props/state (#1679) (01edc2f74)docs: Update migrating-from-eslint-plugin-react.mdx with improved examples and fixes, closes #1654.docs: Add index sections to migration guides for better navigation.examples/react-dom-with-custom-rules: Expand with additional custom rules examples includingforbid-dom-props,jsx-fragments,jsx-handler-names,jsx-max-depth,jsx-no-duplicate-props,jsx-no-literals,jsx-pascal-case,jsx-props-no-spread-multi, andno-adjacent-inline-elements, closes #1653.examples/react-dom-with-custom-rules: Addmax-component-per-filecustom rule example, closes #1437.examples/react-dom-with-custom-rules: Modularize custom rules configuration for better maintainability.website: Migrate to new Fumadocs structure and add LLM routes (/llms.txt,/llms-full.txt,/llms.mdx), closes #1588.test: Enhance test coverage forreact-xandreact-domrules, closes #1663.test: Add comprehensive test coverage forfind-import-source,is-react-api, legacy component detection, hook detection, function init path, and node equality utilities (#1671).test: Add comprehensive unit tests for@eslint-react/varutilities includingcompute-object-type,find-enclosing-assignment-target,is-assignment-target-equal, andis-value-equal(#1672).deps: Update typescript-eslint to ^8.58.0 (#1670).
📝 Documentation
- scripts: Add comprehensive README and more automation scripts (#1673).
docs: Update bug report template with upstream eslint-plugin-react-hooks guidance.- update @eslint-react/kit installation tag from beta to rc (
2da9b4e9d) - update deprecated rule replacements in removed.md (
dc2fe27fb)
✅ Upgrade Checklist
Use this checklist to upgrade from v3.x to v4.2.1:
Package changes
- Install the new
eslint-plugin-react-jsxpackage — this is a new dedicated plugin for React Flavored JSX rules.
ESLint configuration
- Replace
react-x/jsx-key-before-spreadwithreact-jsx/no-key-after-spreadin your ESLint config. - Replace
react-x/jsx-no-comment-textnodeswithreact-jsx/no-comment-textnodesin your ESLint config. - Replace
react-x/no-children-propwithreact-jsx/no-children-propin your ESLint config. - Replace
react-x/no-useless-fragmentwithreact-jsx/no-useless-fragmentin your ESLint config. - Replace
react-dom/no-namespacewithreact-jsx/no-namespacein your ESLint config.
Rule prefix changes in @eslint-react/eslint-plugin
If you use the unified @eslint-react/eslint-plugin package, update the following rule prefixes (slash \/ -> dash -):
- Replace
@eslint-react/rsc/<rule>with@eslint-react/rsc-<rule>in your ESLint config. - Replace
@eslint-react/dom/<rule>with@eslint-react/dom-<rule>in your ESLint config. - Replace
@eslint-react/web-api/<rule>with@eslint-react/web-api-<rule>in your ESLint config. - Replace
@eslint-react/naming-convention/<rule>with@eslint-react/naming-convention-<rule>in your ESLint config. - Replace
@eslint-react/debug/<rule>with@eslint-react/debug-<rule>in your ESLint config.
Review new rules
-
react-jsx/no-children-prop-with-children— new rule that disallows passingchildrenas a prop when children are also passed as nested content. Review your codebase for new reports if using presets.
Removed rules
-
react-x/jsx-dollar -
react-x/jsx-shorthand-boolean -
react-x/jsx-shorthand-fragment -
react-x/unstable-rules-of-props— replaced by Recipes: custom-rules-of-props -
react-x/unstable-rules-of-state— replaced by Recipes: custom-rules-of-state
If you still need these rules, you can enforce them using the new @eslint-react/kit by creating custom rules that implement the desired checks.
@eslint-react/kit migration
- Replace
defineConfig({ rules: [rule1, rule2] })witheslintReactKit().use(rule1).use(rule2).getConfig(). - Replace
hint.defaultComponentwithhint.component.Default. - Remove any
filesoption passed togetConfig()— file extensions are now automatically normalized.
Core API changes (for custom rule authors)
- Replace
useComponentCollector()withgetComponentCollector(). - Replace
useComponentCollectorLegacy()withgetComponentCollectorLegacy(). - Replace
useHookCollector()withgetHookCollector(). - Replace collector return property
.ctxwith.api. - Replace
JsxInspector.from(context)usage with standalone utility functions from@eslint-react/jsx. - Replace
getElementType()withgetElementFullType()from@eslint-react/jsx. - Replace
getElementSelfName()withgetElementSelfType()from@eslint-react/jsx. - Remove usage of deleted ref APIs (
isRefId,isInitializedFromRef,getRefInit,isRefLikeName). - Update JSX-related imports from
@eslint-react/coreto@eslint-react/jsx.
Full Changelog: v3.0.0...v4.2.1