Spreading Props

`{...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.

3 min read Level 2/5 #react#props#spreading
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 →