{...props}
Copies every own property of an object onto a JSX element as props in a single expression.
<Component {...props} />Parameters
| Parameter | Type | Description |
|---|---|---|
$...props | object | null | undefined | Any JavaScript expression. Its own enumerable properties are copied onto the element's props at the point the spread appears. null and undefined contribute nothing. A tag may contain several spreads mixed freely with plain attributes; later entries overwrite earlier ones. |
Return value
Nothing on its own — it contributes the object's own enumerable properties to the element's props at the position where it appears.
Errors
Nothing at runtime — spreading null or undefined simply contributes no props — but an empty `{...}` is a compile-time syntax error.
Changelog
- PHP 18.3.0React began warning when a props object containing a `key` is spread into JSX. Destructure the key out and pass it as its own attribute.
- PHP 19.0.0`ref` is an ordinary prop on function components, so it now flows through a spread instead of requiring forwardRef.
{...expression} inside a JSX tag evaluates the expression and copies its own enumerable properties onto the element's props. It is plain JavaScript object spread: <Avatar {...props} /> just builds the props object by spreading, so nothing React-specific happens at runtime.
When to reach for it
- A thin wrapper that forwards everything it received to one child.
- A component that keeps its own options and passes the remaining DOM attributes through:
function Button({ kind, ...rest }). - Applying a shared defaults object and then overriding one field.
What trips people up
Order decides the winner. Props are applied left to right, so <Input {...props} disabled /> always disables the input, while <Input disabled {...props} /> lets the caller re-enable it. This is the most common surprise by a wide margin.
Spreading onto a DOM tag leaks. Unknown properties are forwarded to the real element and React warns about attributes the DOM does not recognise. Destructure your own props out first.
key does not belong in a spread. React warns when the spread object carries one; pull it out and write it as its own attribute.
The official guidance is to use spread with restraint. Reaching for it in every component usually means the components should be split and the content passed as children instead.
Example
When to use it
- Forward every prop a wrapper component received to the single element it renders
- Split variant props like `kind` or `tone` from the DOM attributes in a design-system button
- Apply a shared defaults object to a component and override one field after it
- Pass a row object from a list straight into an item component without listing each field
Frequently asked questions
How do I pass all props to a child component in React?
Accept them as one object and spread it: `function Wrapper(props) { return <Child {...props} />; }`. Every own enumerable property of `props`, including `children`, is copied onto Child. If the wrapper needs to consume some of them first, destructure those out and spread the remainder: `function Wrapper({ kind, ...rest })`.
Why does React warn that a props object containing a "key" prop is being spread into JSX?
Because `key` is read by React itself and must be written as its own attribute rather than arriving through a spread. Pull it out of the object and pass it directly: `rows.map(({ id, ...rest }) => <Row key={id} {...rest} />)`. The warning was added in React 18.3 and commonly appears when a library's `getItemProps()`-style helper returns an object that already contains a key.
Does a spread override props I wrote before it?
Yes — props are applied left to right and the last value wins, exactly like `Object.assign`. `<Input disabled {...props} />` lets a caller's `disabled: false` re-enable the input, while `<Input {...props} disabled />` forces it off. Put attributes the component must control after the spread, and defaults the caller may replace before it.
More examples
Keep your own props, forward the rest
Renders <button class="PrimaryButton" type="submit">Save</button> and a disabled <button class="SecondaryButton">Cancel</button>. `kind` never reaches the DOM because it was destructured out of the props object; `type`, `disabled` and `children` all travel inside `rest`. Because `className` is written before the spread, a caller could override it — swap the order if the component must own that attribute.
function Button({ kind = "secondary", ...rest }) {
const className =
kind === "primary" ? "PrimaryButton" : "SecondaryButton";
// className is written BEFORE the spread, so a caller
// that passes className wins over the computed one.
return <button className={className} {...rest} />;
}
function Toolbar() {
return (
<div>
<Button kind="primary" type="submit">Save</Button>
<Button disabled>Cancel</Button>
</div>
);
}Position determines which value survives
Prints "A: md / neutral", "B: md / danger" and "C: md / neutral". B overrides the spread because `tone` comes after it. C looks like it sets danger but the spread that follows overwrites it with `neutral` — the same silent overwrite that makes a component ignore an attribute you swear you passed.
const defaults = { size: "md", tone: "neutral" };
function Chip({ size, tone, label }) {
return <li>{label}: {size} / {tone}</li>;
}
function ChipList() {
return (
<ul>
<Chip {...defaults} label="A" />
<Chip {...defaults} tone="danger" label="B" />
<Chip tone="danger" {...defaults} label="C" />
</ul>
);
}Take key out of the object before spreading
Renders "Ada (author)" and "Grace (reviewer)" with stable keys and no console warning. Writing `<Row {...row} />` instead would spread `id` as an ordinary prop and leave the element with no key at all, so React would log "Each child in a list should have a unique \"key\" prop." The "a props object containing a `key` prop is being spread into JSX" warning is a different case — it fires only when the spread object literally has a `key` property, as it would if these rows were written `{ key: "a1", name: "Ada" }`. Destructuring `id` out also keeps it from arriving as an unused prop on Row.
const rows = [
{ id: "a1", name: "Ada", role: "author" },
{ id: "b2", name: "Grace", role: "reviewer" }
];
function Row({ name, role }) {
return <li>{name} ({role})</li>;
}
function RowList() {
return (
<ul>
{rows.map(({ id, ...rest }) => (
<Row key={id} {...rest} />
))}
</ul>
);
}Two spreads plus explicit overrides
The email field ends up with type="email" because `rest` is spread after `base`, while the note field falls back to base's type="text". Both inputs are read-only: `readOnly` sits last in the tag, so no caller can turn it off. This is the standard layering — library defaults, then caller props, then the attributes the component insists on.
const base = { type: "text", autoComplete: "off" };
function Field({ label, id, ...rest }) {
return (
<p>
<label htmlFor={id}>{label} </label>
<input id={id} {...base} {...rest} readOnly />
</p>
);
}
function Form() {
return (
<form>
<Field id="email" label="Email" type="email" value="[email protected]" />
<Field id="note" label="Note" value="pinned" />
</form>
);
}
Discussion