Question

React JSX Spread Attributes: What ...props Does

javascriptreactjsspread-syntax

Question

What do the three dots (...) do in this React JSX code, what is this syntax called, and how does it affect the props passed to Modal?

<Modal {...this.props} title="Modal heading" animation={false}>

Specifically, how are this.props, title, and animation combined when the component is rendered?

Short Answer

The ... syntax in JSX is called a spread attribute (or props spread). It takes the properties from an object and passes them to a component as individual props. In this example, this.props is spread into Modal, then the explicitly written title and animation props are applied. Because they appear later, they override matching values from this.props.

Concept

In React JSX, an expression such as:

<Component {...propsObject} />

uses a spread attribute. It copies the enumerable properties of propsObject and supplies them as props to Component.

For example:

const modalProps = {
  isOpen: true,
  size: "large",
  title: "Old title"
};

<Modal {...modalProps} />

is approximately equivalent to:

<Modal isOpen={true} size="large" title="Old title" />

In the original code:

<Modal {...this.props} title="Modal heading" animation={false}>

React receives props from this.props, plus a fixed title and animation value. If this.props already contains title or animation, the explicitly written values win because they come later.

This matters because components often receive many props. Spreading can forward them without manually listing every one, but it can also make it less obvious which props are being passed.

Mental Model

Think of a props object as a bag of labelled items:

{ size: "large", isOpen: true, title: "Old title" }

{...this.props} means: “Open this bag and place every labelled item on the Modal component.”

Then JSX adds two more labels:

  • title: "Modal heading"
  • animation: false

If a label is already present, the later label replaces it. So the explicit title is like putting a new title label over the old one.

Take Quiz

Syntax and Examples

The JSX syntax is:

<Component {...object} />

The expression after ... must evaluate to an object-like value whose properties can become props.

function Button(props) {
  return <button disabled={props.disabled}>{props.children}</button>;
}

const buttonOptions = {
  disabled: true,
  "aria-label": "Save changes"
};

function SaveButton() {
  return <Button {...buttonOptions}>Save</Button>;
}

Button receives:

  • disabled: true
  • aria-label: "Save changes"
  • children: "Save"

You can combine spread props with explicit props:

const options = {
  theme: "dark",
  title: "From options"
};

<Panel {...options} title="Fixed title" />

The final title is "Fixed title", since it is written after {...options}.

You can also intentionally let an object override a default:

<Panel title="Default title" {...options} />

Here, options.title overrides "Default title" if it exists.

Step by Step Execution

Consider this class component example:

class ModalWrapper extends React.Component {
  render() {
    return (
      <Modal {...this.props} title="Modal heading" animation={false}>
        Settings
      </Modal>
    );
  }
}

Suppose ModalWrapper is used like this:

<ModalWrapper isOpen={true} title="Account" animation={true} size="large" />

At render time, this.props is approximately:

{
  isOpen: true,
  title: "Account",
  animation: true,
  size: "large"
}

The JSX is processed in order:

  1. {...this.props} forwards isOpen, title, animation, and size.
  2. title="Modal heading" replaces the forwarded title value.
  3. animation={false} replaces the forwarded animation value.
  4. Settings becomes the children prop.

Therefore, Modal effectively receives:

{
  isOpen: true,
  title: "Modal heading",
  animation: false,
  size: "large",
  children: "Settings"
}

Real World Use Cases

Spread attributes are useful when a wrapper component needs to forward props.

Reusable wrapper components

function Card({ className, ...rest }) {
  return <section className={`card ${className ?? ""}`} {...rest} />;
}

A caller can provide standard attributes such as id, aria-label, and event handlers without Card manually declaring each one.

Forwarding form input props

function TextInput({ label, ...inputProps }) {
  return (
    <label>
      {label}
      <input {...inputProps} />
    </label>
  );
}

<TextInput label="Email" type="email" required />

Applying configuration objects

const chartOptions = {
  data: salesData,
  height: 320,
  showLegend: true
};

<Chart {...chartOptions} />

Supplying defaults that callers may override

<Button type="button" {...buttonProps} />

If buttonProps.type exists, it can override the default because the spread appears later.

Take Quiz

Real Codebase Usage

In real projects, props spreading is usually paired with destructuring so a component consumes its own props and forwards the rest.

function Modal({ title, animation = true, children, ...modalProps }) {
  return (
    <div {...modalProps} data-animation={animation}>
      <h2>{title}</h2>
      {children}
    </div>
  );
}

This pattern has clear responsibilities:

  • title, animation, and children are used by Modal itself.
  • ...modalProps contains remaining props to forward to the underlying element.

A common pattern for defaults is:

function SubmitButton(props) {
  return <button type="submit" {...props} />;
}

This permits callers to override type. If the type must never change, reverse the order:

function SubmitButton(props) {
  return <button {...props} type="submit" />;
}

Use this deliberately. Attribute order is part of the component's API behavior.

When forwarding props to a DOM element, filter out custom props first. Otherwise React may receive attributes that do not belong on that element.

function Alert({ tone, ...divProps }) {
  return <div {...divProps} className={`alert alert-${tone}`} />;
}

Common Mistakes

Assuming ... is a React-only operator

The underlying ... is JavaScript spread syntax. JSX uses it in a special attribute position to spread object properties into component props.

Forgetting that order changes the result

const props = { title: "From object" };

<Modal title="Default" {...props} />

The title is "From object", not "Default", because the spread comes last.

To force the fixed title:

<Modal {...props} title="Default" />

Spreading an array instead of a props object

// Incorrect: array items are not named props for this purpose.
<Modal {...["open", "large"]} />

Use an object with named properties:

<Modal {...{ isOpen: true, size: "large" }} />

Accidentally forwarding internal custom props to a DOM element

function Box(props) {
  return <div {...props} />;
}

<Box layout="compact" />

layout is an internal component prop, not necessarily a useful DOM attribute. Extract it first:

function Box({ layout, ...divProps }) {
  return <div {...divProps} className={`box box-${layout}`} />;
}

Using spread when explicit props would be clearer

For two or three important props, writing them explicitly can make the component easier to understand:

<Modal isOpen={isOpen} onClose={onClose} title={title} />

Avoid blindly passing an entire object when it hides what the component depends on.

Comparisons

Syntax or patternPurposeExample
JSX props spreadPass object properties as component props<Modal {...props} />
Object spreadCopy or merge properties into a new objectconst next = { ...props, title: "New" };
Array spreadExpand array items where values are expectedconst all = [...first, ...second];
Explicit propsName each prop directly<Modal isOpen={true} size="large" />
childrenContent between component tags<Modal>Content</Modal>

JSX spread attributes and JavaScript object spread use similar syntax, but they occur in different places:

const modalProps = { isOpen: true };

// Object spread: creates an object.
const finalProps = { ...modalProps, animation: false };

// JSX spread attribute: passes properties as props.
<Modal {...finalProps} />

A useful equivalence is:

<Modal {...this.props} title="Modal heading" animation={false} />

roughly corresponds to:

const finalProps = {
  ...this.props,
  title: "Modal heading",
  animation: false
};

followed by rendering Modal with finalProps.

Take Quiz

Cheat Sheet

// Spread every property in an object as props
<Component {...props} />

// Explicit props after a spread override matching object properties
<Component {...props} title="Fixed" />

// A spread after explicit props can override them
<Component title="Default" {...props} />

// Consume selected props and forward the rest
function Input({ label, ...inputProps }) {
  return <input {...inputProps} aria-label={label} />;
}
  • Name: JSX spread attribute, props spread, or spread props.
  • The value after ... should be an object.
  • Spread order is left to right; later values take precedence.
  • Content between tags becomes children.
  • Use destructuring to prevent internal props from reaching DOM elements.
  • Prefer explicit props when clarity is more important than generic forwarding.

FAQ

What is {...this.props} called in React?

It is called a JSX spread attribute or props spread. It passes the properties in this.props to the component.

Does {...this.props} copy every prop to Modal?

It forwards the properties available in this.props. Explicit attributes written afterward can replace values with the same prop name.

Which value wins when spread props and explicit props have the same name?

The value written later wins. In <Modal {...props} title="New" />, title is "New".

Is ...props the same as React children?

No. Spread attributes pass named props from an object. Content between tags, such as <Modal>Text</Modal>, is passed separately as children.

Can I use spread props with HTML elements?

Yes. For example, <input {...inputProps} /> is common. Remove custom internal props before spreading onto a DOM element.

Why does the example use this.props?

this.props is the props object inside a React class component. In a function component, the equivalent is usually a props parameter or destructured values.

Should I always use props spread?

No. Use it for intentional forwarding or configuration objects. Prefer explicit props when spreading would obscure the component's important inputs.

Take Quiz

Mini Project

Description

Build a reusable TextInput wrapper that displays a label and forwards ordinary input attributes such as type, placeholder, required, and onChange. The project demonstrates how to consume component-specific props while safely forwarding the remaining props to an HTML <input>.

Goal

Create a labelled email input that uses JSX spread attributes to forward input options.

Requirements

Include a TextInput component that accepts a label prop. Forward all remaining props to an <input> element. Render an email field with a placeholder and the required attribute. Use a fixed type="email" that cannot be overridden by forwarded props.

Take Quiz

Keep learning

Related questions

View more