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?
-
[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 Answers
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>);
}
}

- 1,628
- 1
- 18
- 34

- 3,895
- 7
- 38
- 63
-
2I 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
-
1Found 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
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 />;
};

- 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: `
`. – certainlyakey Jun 20 '20 at 10:59- dd1
- dd2
-
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
Weeks back I had a scenario of carousal to be implemented in react, nothing fancy just simple toggling of active class. I followed this approch, works like a charm but let me know this is a good approach.
{
this.props.children.map((slide, index) => {
return React.cloneElement(slide, {
key: index,
className: (this.state.currentActiveIndex === index) ?'active' : ''
});
})
}

- 310
- 4
- 8
-
2Using `cloneElement` is the best approach IMO. You are actually using what the API it's for. – denyzprahy Jan 26 '19 at 22:17
-
1Your active className approach wasn't what I came here looking for, but it's better than the one I implemented. Thanks for the help! – Christopher Marshall Jul 01 '20 at 21:38
You can pass a prop down to the child and it can choose what class to apply (or just pass the class name but this is more semantic):
<Parent contentVisible={true}>
<Child />
</Parent>
In your child render:
const classes = [];
if (props.contentVisible)
classes.push('visible');
<div className={classes.join(' ')} />

- 62,658
- 20
- 139
- 163
Here's modern solution that's type-safe (Typescript 5.0, React 18.2):
import * as React from 'react';
import type { ReactNode, ReactElement, ReactPortal, PromiseLikeOfReactNode, ReactFragment } from 'react';
type StylizeChildrenProps = {
children?: ReactNode
className: React.HTMLAttributes<any>['className']
}
export function StylizeChildren({ children, className = '' }: StylizeChildrenProps) {
if (children == null) return null;
className = className.trim();
if (!className) return <>{children}</>
return <>
{React.Children.map(children, child => addClassToNode(child, className))}
</>
}
// Separate out into its own function because Promise-like nodes require this to be recursive
export function addClassToNode(node: ReactNode, className: string): ReactNode {
if (node == null) {
node satisfies null | undefined
return node
}
if (typeof node !== 'object') {
node satisfies string | number | boolean
// wrap in a span, somewhat arbitrary decision
return <span className={className}>{node}</span>
}
if ('props' in node) {
node satisfies ReactElement | ReactPortal
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const existing: unknown = node?.props?.className;
if (existing && typeof existing === 'string') {
className = `${existing} ${className}`
}
return React.cloneElement(node, { className })
}
if ('then' in node) {
node satisfies PromiseLikeOfReactNode
return node.then(n => addClassToNode(n, className))
}
node satisfies ReactFragment
// wrap in div, somewhat arbitrary decision
return <div className={className}>{node}</div>
}
It would be straightforward to modify this to do other things when it encounters non-object types or ReactFragments. For example, a ReactFragment is an Iterable, so instead of wrapping it in a div, you could iterate through all of its children and give it the class instead.
The satisfies
statements are there because I think they make it more clear what's happening and will reveal some otherwise nasty bugs if the underlying types or React APIs ever change. If you're running a Typescript version lower than 4.9, just remove them and everything should still work fine.

- 31
- 2
Inside render method of your component:
var childClasses = [],
childClassNames;
if (condition) {
childClasses.push('my-class-name');
}
childClassNames = childClasses.join(' ');
return (<div className={childClassNames}>
.... (your component here)
</div> );

- 7,823
- 7
- 45
- 66
-
2I dont want to do it in each of the components, I want the component that contains them to do the testing and add the class if neccessary – Golan Kiviti Aug 30 '16 at 12:10
-
1Not sure what exactly are you trying to achieve. Your parent component can calculate all the necessary classes and pass them as props to the children. – Maggie Aug 30 '16 at 12:13