jsx-no-jsx-as-prop
Disallow render-local JSX allocations passed through JSX props.
Deprecated
- Lifecycle: Deprecated, frozen, and non-recommended.
- Deprecated since:
v3.0.0 - Available until:
v4.0.0 - Use instead:
no-unstable-react-values
The replacement consolidates JSX, function, array, and object prop stability checks behind one rule and one intrinsic-element policy. Do not enable both.
Targeted pattern scope
This rule reports JSX elements and fragments used as prop expressions inside a function or class render scope. It follows logical and conditional branches and resolves a single same-function const initializer.
Normal JSX children are not props for this rule and are not reported. Module-level JSX constants are treated as stable. Intrinsic attributes can be exempted by name.
What this rule reports
A JSX expression creates a new React element object. Passing that object through a prop can defeat shallow comparison when the receiver is memoized and the element is otherwise stable. Composition through children is often clearer, but JSX-as-prop APIs can also be intentional.
Why this rule exists
Element objects participate in reference comparisons just like arrays and objects. The rule exposes JSX-valued props when a component API expects their identities to remain stable.
❌ Incorrect
function Page() {
return <Layout header={<Header />} />; // New element object every render.
}
function Page() {
const header = <Header />;
return <Layout header={header} />; // The render-local const is still unstable.
}
✅ Correct
function Page() {
return (
<Layout>
<Header /> {/* Composition is outside this rule's prop-specific scope. */}
</Layout>
);
}
const header = <Header />;
function Page() {
return <Layout header={header} />;
}
Behavior and migration notes
This rule reports only. Moving JSX outside a component can accidentally freeze props or context, while adding useMemo can introduce unnecessary dependencies.
React Compiler can automatically memoize values and components in supported builds. Enable this opt-in rule only when a component API deliberately requires stable element identity. It is included by both the all and allStrict presets.
Options
interface Options {
nativeAllowList?: "all" | readonly string[];
}
Default: { nativeAllowList: "all" }
nativeAllowList ignores case-insensitive attribute names on intrinsic JSX elements. The default "all" keeps the rule focused on component props because intrinsic attributes do not participate in a child component's prop-identity contract. Set it to [] to check every intrinsic attribute, or provide selected names to ignore.
ESLint flat config example
import etcMisc from "eslint-plugin-etc-misc";
export default [
{
plugins: { "etc-misc": etcMisc },
rules: {
"etc-misc/jsx-no-jsx-as-prop": "warn",
},
},
];
When not to use it
Disable this rule for render-prop or slot APIs where JSX-valued props are the intended interface, when receiver identity does not affect rendering, or when React Compiler owns memoization.
Package documentation
The rule is a clean-room implementation informed by eslint-plugin-react-perf. It intentionally remains outside the recommended preset because JSX-valued props are often valid API design.
Rule catalog ID: R016
Further reading
Adoption resources
- Start at warning level in CI, then move to error after cleanup.
- Review whether stable identity is observable before changing the component API.