{"record":{"id":"cec032d0601bb6f2","repo":"oxc-project/oxc","slug":"key-prop-must-be-placed-before-any-spread","errorCode":null,"errorMessage":"\"key\" prop must be placed before any `{...spread}`","messagePattern":"\"key\" prop must be placed before any `(.+?)`","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/react/jsx_key.rs","lineNumber":44,"sourceCode":"};\n\nconst TARGET_METHODS: [&str; 3] = [\"flatMap\", \"from\", \"map\"];\n\nfn missing_key_prop_for_element_in_array(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(r#\"Missing \"key\" prop for element in array.\"#).with_label(span)\n}\n\nfn missing_key_prop_for_element_in_iterator(iter_span: Span, el_span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(r#\"Missing \"key\" prop for element in iterator.\"#)\n        .with_help(r#\"Add a \"key\" prop to the element in the iterator (https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key).\"#)\n        .with_labels([\n            iter_span.label(\"Iterator starts here.\"),\n            el_span.label(\"Element generated here.\"),\n        ])\n}\n\nfn key_prop_must_be_placed_before_spread(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(r#\"\"key\" prop must be placed before any `{...spread}`\"#)\n        .with_help(\"To avoid conflicting with React's new JSX transform: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html\")\n        .with_label(span)\n}\n\nfn duplicate_key_prop(key_value: &str, span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(format!(\"Duplicate key '{key_value}' found in JSX elements\"))\n        .with_help(\"Each child in a list should have a unique 'key' prop\")\n        .with_label(span)\n}\n\n#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]\n#[schemars(transparent)]\npub struct JsxKey(Box<JsxKeyConfig>);\n\n#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema)]\n#[serde(rename_all = \"camelCase\", default, deny_unknown_fields)]\npub struct JsxKeyConfig {\n    /// When true, require key prop to be placed before any spread props","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/react/jsx_key.rs#L26-L62","documentation":"react/jsx-key diagnostic controlled by the checkKeyMustBeforeSpread option (default TRUE in oxlint — intentionally stricter than eslint-plugin-react, whose default is false). It fires when a 'key' attribute is written after a {...spread} attribute in the same JSX opening element. With React's new JSX transform, later spread props overwrite previously-set attributes, so <div key=\"a\" {...props}/> would have its key silently dropped; the key must come before any spread.","triggerScenarios":"<Component {...props} key={id}/>; also key appearing after any JSXSpreadAttribute, e.g. <div {...rest} key='row'/>. Only when checkKeyMustBeforeSpread is true (the default), and only when a literal key attribute follows a spread attribute.","commonSituations":"Forwarding props with {...rest} while adding a key; code written for the classic JSX transform where ordering did not matter; migrating a codebase to the automatic runtime (react/jsx-runtime) where this ordering becomes load-bearing.","solutions":["Move the key attribute before the spread: <Component key={id} {...props}/>","Alternatively remove the separate key and pass it inside the spread object if that object is constructed for this element","If you must match old eslint-plugin-react behavior, set { \"rules\": { \"react/jsx-key\": [\"error\", { \"checkKeyMustBeforeSpread\": false }] } } in .oxlintrc.json","Verify with the React 17+ automatic transform that keys are no longer being dropped after fixing"],"exampleFix":"// before\n<Component {...props} key={item.id} />\n\n// after\n<Component key={item.id} {...props} />","handlingStrategy":"validation","validationCode":"npx oxlint -D react/jsx-key src/  # checkKeyMustBeforeSpread defaults to true in oxlint","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Write key as the first attribute whenever spreading props: <El key={id} {...props}/>","Understand why: with the automatic JSX transform, a spread after key overwrites the key","Keep the default checkKeyMustBeforeSpread: true — oxlint deliberately defaults stricter than the ESLint plugin for correctness"],"tags":["react","jsx","list-key","spread-props","jsx-transform","oxlint","lint"],"backgroundTag":"react-key-before-spread","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}