How Do You Pass Props to `{this.props.children}`?

Naveera A.

The Problem

You have a parent component that acts as a wrapper around other components. Can it pass props to its children?

Let’s say we have a component called RadioGroup that has a number of children components called RadioInput, like so:

<RadioGroup>
    <RadioInput value="first">First</RadioInput>
    <RadioInput value="second">Second</RadioInput>
    <RadioInput value="third">Third</RadioInput>
</RadioGroup>

The RadioInput component just renders an <input> element:

const RadioInput = (props) => {
  return (
    <div>
      <label>
        {props.children}
        <input type="radio" name={props.name} value={props.value} />
      </label>
    </div>
  );
};

To group input elements together, they must have the same name attribute. We can do it manually, like this:

<RadioGroup>
    <RadioInput name="group1" value="first">First</RadioInput>
    <RadioInput name="group1" value="second">Second</RadioInput>
    <RadioInput name="group1" value="third">Third</RadioInput>
</RadioGroup>

But is there a way to add the name attribute programmatically by passing it as a prop to the parent component? For example:

<RadioGroup name="group1">
    <RadioInput value="first">First</RadioInput>
    <RadioInput value="second">Second</RadioInput>
    <RadioInput value="third">Third</RadioInput>
</RadioGroup>

The Solution

To pass additional props to the children from within the parent component, you need to clone the children components using React.cloneElement().

The React.cloneElement() API clones an element and returns a new React element. The cool thing is that the resulting element will have all of the original element’s props, with the new props merged in.

For example:

const newElement = React.cloneElement(originalElement, {
  extraProp: "Some extra prop",
});

Here, newElement will have all the props from the originalElement, along with the extraProp.

In our original example, let’s say we have the RadioGroup component defined as follows:

const RadioGroup = (props) => {
  return <div>{props.children}</div>;
};

You can write a function renderChildren and use it inside the return statement:

const RadioGroup = (props) => {
  const renderChildren = () => {
    return props.children;
  };

  return <div>{renderChildren()}</div>;
};

Now you can loop over all props.children using the map function and clone each child with React.cloneElement(). While cloning we will add name to the existing props, like so:

const RadioGroup = (props) => {
  const renderChildren = () => {
    return React.Children.map(props.children, (child) => {
      return React.cloneElement(child, {
        name: props.name,
      });
    });
  };

  return <div>{renderChildren()}</div>;
};

This way all the children components will have the name attribute set to whatever you pass to the RadioGroup component.

Join the discussionCome work with us
Share on Twitter
Bookmark this page
Ask a questionImprove this Answer

Related Answers

A better experience for your users. An easier life for your developers.

Try Sentry For FreeRequest a Demo
    TwitterGitHubDribbbleLinkedin
© 2022 • Sentry is a registered Trademark
of Functional Software, Inc.