`{...rest}` Forwards Whatever the Caller Passed
Spreading Props
Spreading props lets you forward arbitrary HTML/component attributes from a wrapper component down to the element it renders.
What you'll learn
- Spread props onto a child element
- Pick certain props off, forward the rest
- Recognize when spreading hurts more than it helps
A common pattern: a wrapper component that adds a little bit (some styling, a hook) but should otherwise behave like the underlying element. Spreading props makes this clean.
Forward Everything
function Button(props) {
return <button className="btn" {...props} />;
}
<Button onClick={save} disabled={busy} aria-label="Save">Save</Button> Now onClick, disabled, aria-label, AND children all flow
through to the underlying <button>. You didn’t write any of that
forwarding by hand.
Pick Some, Forward the Rest
The ...rest pattern keeps your own props separate:
function Button({ kind = "primary", ...rest }) {
return <button className={`btn btn--${kind}`} {...rest} />;
}
<Button kind="danger" onClick={remove}>Delete</Button> kind is your prop; the underlying <button> shouldn’t see it.
Everything else (onClick, disabled, children, etc.) passes
through unchanged.
Order Matters
When the spread comes AFTER your own attributes, the caller can override them:
function Input(props) {
return <input type="text" {...props} />;
// ↑ default ↑ overrides "text" if caller passed type
}
<Input type="email" /> // becomes type="email" Flipped, your value wins:
function Input(props) {
return <input {...props} type="text" />;
// ↑ always "text", even if caller passed something else
} Pick the order that matches the intent.
Merging className
Spreading clobbers — {...props} replaces className. To merge,
combine the strings yourself:
function Button({ className = "", ...rest }) {
return (
<button className={`btn ${className}`.trim()} {...rest} />
);
}
<Button className="primary">OK</Button>
// → class="btn primary" For complex class merging, libraries like clsx or tailwind-merge
are popular.
When Not to Spread
Good fit for spreading: leaf-level wrappers around <input>,
<button>, etc. Bad fit: deep business components — list each prop.
Up Next
Now that you can build small pieces and forward props, composition turns them into real UIs.
Composition →