react/jsx-key
Require a key prop on elements in arrays and iterators
React uses key to tell list items apart from one render to the next. Without it, React warns at run time and matches items by position. After an insert or a reorder, an item can then end up with its neighbor's state, such as the text typed into an input.
The rule looks at elements returned from a .map() or Array.from() callback, and at elements in an array literal that React renders as a list: one that's a child of an element, or that a function returns. It skips lists passed to React.Children.toArray(), because that adds keys itself.
This rule is on by default if your package.json depends on react.
Configure#
On by default as an error. To turn it off:
[lint.rules]
"react/jsx-key" = "off" # or "warn"Every option, set to its default:
[lint.rules]
"react/jsx-key" = ["error", {
checkFragmentShorthand = false,
checkKeyMustBeforeSpread = false,
warnOnDuplicates = false,
checkArraysOutsideJSX = false,
}]Examples#
const list = (
<ul>
{users.map(user => <li>{user.name}</li>Missing key prop for element in iterator)}
</ul>
);
const tabs = <nav>{[<Tab key="home" />, <Tab />Missing key prop for element in array]}</nav>;
const stars = Array.from({ length: 5 }, () => <Star />Missing key prop for element in iterator);const list = (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
const tabs = <nav>{[<Tab key="home" />, <Tab key="settings" />]}</nav>;
const panels = React.Children.toArray([<Panel />, <Panel />]);An array that's only a place to keep elements doesn't need keys:
function Wizard({ step }) {
const steps = [<Address />, <Payment />, <Review />];
return steps[step];
}
const card = <Card actions={[<a href="#edit">Edit</a>, <a href="#more">More</a>]} />;Options#
| Option | Default | What it does |
|---|---|---|
checkFragmentShorthand | false | Also report <>...</> in a list. It can't take a key, so use <React.Fragment key={...}>. |
checkKeyMustBeforeSpread | false | Also report a key that comes after a {...spread}. |
warnOnDuplicates | false | Also report siblings that have the same key. |
checkArraysOutsideJSX | false | Also report elements in every other array literal. |
Only bun lint has checkArraysOutsideJSX. With an ESLint config file every array literal is checked, as in eslint-plugin-react.
{ "checkArraysOutsideJSX": true }2 problemsconst icons = [<Home />Missing key prop for element in array, <User />Missing key prop for element in array];With checkFragmentShorthand:
{ "checkFragmentShorthand": true }1 problemconst rows = users.map(user => (
<>Missing key prop for element in iterator. Shorthand fragment syntax does not support providing keys. Use React.Fragment instead
<dt>{user.name}</dt>
<dd>{user.email}</dd>
</>
));{ "checkFragmentShorthand": true }No problemsconst rows = users.map(user => (
<React.Fragment key={user.id}>
<dt>{user.name}</dt>
<dd>{user.email}</dd>
</React.Fragment>
));When a key comes after a spread, the automatic JSX runtime falls back to createElement for that element. checkKeyMustBeforeSpread reports it:
{ "checkKeyMustBeforeSpread": true }1 problemconst rows = users.map(user => <Row {...user} key={user.id} />key prop must be placed before any {...spread}, to avoid conflicting with React’s new JSX transform: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html);{ "checkKeyMustBeforeSpread": true }No problemsconst rows = users.map(user => <Row key={user.id} {...user} />);With warnOnDuplicates:
{ "warnOnDuplicates": true }2 problemsconst tabs = [<Tab key="home"key prop must be unique />, <Tab key="home"key prop must be unique />];