36

im using react and I have a component that simply needs to render the children and add them a class according to a condition. Whats the best way of doing it?

Golan Kiviti
  • 3,895
  • 7
  • 38
  • 63
  • [This](http://stackoverflow.com/questions/26863938/modify-attributes-of-children-in-reactjs-component) should help you. – Cosmin Ababei Sep 17 '16 at 08:33
  • My suggestion is to try to solve it at the CSS level. If you're using tailwind, add the "tailwind variants" plugin. – Mohsen May 30 '23 at 22:59

6 Answers6

39

I figured it out a week ago, this is what I wanted :

export default class ContainerComponent extends React.Component {
    constructor(props) {
        super(props);

        this.modifyChildren = this.modifyChildren.bind(this);
    }

    modifyChildren(child) {
        const className = classNames(
            child.props.className,
            {...otherClassses}
        );

        const props = {
            className
        };

        return React.cloneElement(child, props);
    }
    render() {
        return (<div>
            {React.Children.map(this.props.children, child => this.modifyChildren(child))}
        </div>);
    }
}
wulftone
  • 1,628
  • 1
  • 18
  • 34
Golan Kiviti
  • 3,895
  • 7
  • 38
  • 63
  • 2
    I tried this solution, however I get an error from the render function, "child is not defined." If I change to an anonymous function there, instead of calling a class method (this.modifyChildren in your example), the error goes away and everything works fine. This works with both "fat arrow" and traditional JS anonymous functions. Can't figure out why it works for you and not for me when our code is nearly identical. – Dave Munger Aug 03 '17 at 17:11
  • 1
    Found this article that might help others - https://learn.co/lessons/react-this-props-children, looks like a v similar solution :) – Ash Jul 16 '18 at 09:34
23

For the sake of simplicity:

const StyleInjector = ({ children }) => {
   const StyledChildren = () =>
    React.Children.map(children, child =>
      React.cloneElement(child, {
        className: `${child.props.className} ${PUT_YOUR_CLASS_HERE}`
      })
    );

  return <StyledChildren />;
};
Kerem atam
  • 2,387
  • 22
  • 34
  • Replace the args of StyleInjector with `{children, className}` and `PUT_YOUR_CLASS_HERE` with `className` if you want to set an extra class from outside. Usage example: `
  • dd1
  • dd2
  • `. – certainlyakey Jun 20 '20 at 10:59
  • 1
    @certainlyakey it is actually intentional, imagine if you already have access to className on top-level component, why would you need to wrap it with another component? You can just give it to the child. Well, there can be a unique case where you might apply the className according to local state of Wrapper. But in that case I think it is kind of miss leading to other developers that they expect these classNames to be applied. – Kerem atam Jun 21 '20 at 18:27