I have a Card
component and a CardGroup
component, and I'd like to throw an error when CardGroup
has children that aren't Card
components. Is this possible, or am I trying to solve the wrong problem?
15 Answers
For React 0.14+ and using ES6 classes, the solution will look like:
class CardGroup extends Component {
render() {
return (
<div>{this.props.children}</div>
)
}
}
CardGroup.propTypes = {
children: function (props, propName, componentName) {
const prop = props[propName]
let error = null
React.Children.forEach(prop, function (child) {
if (child.type !== Card) {
error = new Error('`' + componentName + '` children should be of type `Card`.');
}
})
return error
}
}

- 6,189
- 7
- 40
- 45
-
21I don't know why, but ```child.type === Card``` isn't working in my setup. However I got it working by using ```child.type.prototype instanceof Card```. My React version is 15.5.4 – Veikko Karsikko Jul 11 '17 at 15:20
-
why not just throw it then and there, instead of returning an Error value. – user2167582 Sep 10 '17 at 19:03
-
6@user2167582 Because that's the expected API for prop validation functions. [Official docs](https://github.com/facebook/prop-types/blob/master/README.md) include the following comment in example code: _You can also specify a custom validator. It should return an Error object if the validation fails. Don't `console.warn` or throw, as this won't work inside `oneOfType`_. – Diego V Sep 11 '17 at 11:05
-
6Where's the docs of `child.type`? Can someone send link it please? – stevemao Sep 21 '17 at 07:50
-
this worked for me React.Children.forEach(props[propName], function (child) { if (child.type && child.type.name !== 'Card') { error = new Error('Blabla ´' + componentName + ' some error'); } }) – nerdess Feb 22 '18 at 13:12
-
1@VeikkoKarsikko That's the only thing that worked for me. Thank you! This should be an answer, rather than a comment – Apr 10 '18 at 10:29
-
@nerdess using child.type.name is not going to work in the minified production build...! – Leon Feb 22 '19 at 09:42
-
@VeikkoKarsikko ```instanceof``` should work when you're using class components, but will not when you're using function components. In the case of the latter, use the ```child.type === Card``` comparison. – Clinton Chau Dec 03 '20 at 20:19
-
Worth noting that `React.Children` iterates only through top-level children, so if you want to check the type of a child, you'll need to do so with `child.props.children`. – Nicolás de Ory Feb 01 '21 at 13:26
-
I'm on an MDX setup and only way I got it working was `child.props.mdxType === 'TabPanel'` – any_h Jan 05 '22 at 22:51
You can use the displayName for each child, accessed via type:
for (child in this.props.children){
if (this.props.children[child].type.displayName != 'Card'){
console.log("Warning CardGroup has children that aren't Card components");
}
}

- 6,684
- 6
- 24
- 44

- 3,113
- 1
- 18
- 24
-
5Make sure to check whether the current environment is development or production. propTypes validation is not triggered in production for performance. Using customProp in propTypes will be helpful. – Ryan Rho Apr 28 '15 at 23:43
-
18You shouldn't do this because `props.children` is an [opaque data type](https://en.wikipedia.org/wiki/Opaque_data_type). Better use `React.Children` utilities as shown [here](http://stackoverflow.com/a/36424582/1385678). – Diego V Apr 06 '16 at 15:51
-
34
-
@MoeSattler is that true? I thought uglify would leave strings like that alone, because it can't know for certain whether they're being used elsewhere or not.. – jrz Jun 23 '17 at 01:42
-
1
-
4As @RyanRho pointed out this can cause issue when running React in production mode. Instead I added a defaultProp to the child component e.g `static defaultProps = { isCard: true}` and then checked for this e.g `if (!this.props.children[child].props.isCard) { ... }` – Hedley Smith Jul 26 '17 at 12:37
-
5That "helped me", but I used `name` instead of `displayName` (this last one doesn't worked for me) – ArCiGo Jan 23 '18 at 23:03
-
11Never use the displayName since in production it might be stripped out! – HaNdTriX Feb 05 '18 at 14:52
-
Wouldn't you want to use `child.type.prototype instanceof Card` instead? Then minification/uglifying shouldn't cause an issue. – CTS_AE Nov 09 '20 at 22:45
-
1Related: [How to get children type in react](https://stackoverflow.com/questions/39212960/how-to-get-children-type-in-react) (`name` might be a better option than `displayName`) – Henry Woody Feb 08 '21 at 19:55
For those using a TypeScript version. You can filter/modify components like this:
this.modifiedChildren = React.Children.map(children, child => {
if (React.isValidElement(child) && (child as React.ReactElement<any>).type === Card) {
let modifiedChild = child as React.ReactElement<any>;
// Modifying here
return modifiedChild;
}
// Returning other components / string.
// Delete next line in case you dont need them.
return child;
});

- 1,821
- 2
- 14
- 15
You can use a custom propType function to validate children, since children are just props. I also wrote an article on this, if you want more details.
var CardGroup = React.createClass({
propTypes: {
children: function (props, propName, componentName) {
var error;
var prop = props[propName];
React.Children.forEach(prop, function (child) {
if (child.type.displayName !== 'Card') {
error = new Error(
'`' + componentName + '` only accepts children of type `Card`.'
);
}
});
return error;
}
},
render: function () {
return (
<div>{this.props.children}</div>
);
}
});

- 658
- 1
- 7
- 19

- 542
- 1
- 4
- 10
-
-
Thanks, @DiegoV. I think you can also declare `static propTypes = {}` in the class definition. – Con Antonakos Apr 05 '16 at 17:29
-
I like that syntax too but class properties are still just a proposal for ES7. Personally I'll wait to see if it gets standardized :) – Diego V Apr 06 '16 at 15:38
-
4
Use the React.Children.forEach
method to iterate over the children and use the name
property to check the type:
React.Children.forEach(this.props.children, (child) => {
if (child.type.name !== Card.name) {
console.error("Only card components allowed as children.");
}
}
I recommend to use Card.name
instead of 'Card'
string for better maintenance and stability in respect to uglify.
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

- 2,446
- 1
- 14
- 12
-
1Working only if I change name to displayName **if (child.type.displayName !== Card.name)** – pacocom May 26 '20 at 11:48
One has to use "React.isValidElement(child)" along with "child.type" if one is working with Typescript in order to avoid type mismatch errors.
React.Children.forEach(props.children, (child, index) => {
if (React.isValidElement(child) && child.type !== Card) {
error = new Error(
'`' + componentName + '` only accepts children of type `Card`.'
);
}
});

- 579
- 6
- 5
-
I have an error with this code: [ts] This condition will always return 'false' since the types 'string | ComponentClass<{}, any> | StatelessComponent<{}>' and 'typeof MyChildClass' have no overlap. [2367] – Frédéric Mascaro Jan 09 '19 at 10:14
You can add a prop to your Card
component and then check for this prop in your CardGroup
component. This is the safest way to achieve this in React.
This prop can be added as a defaultProp so it's always there.
class Card extends Component {
static defaultProps = {
isCard: true,
}
render() {
return (
<div>A Card</div>
)
}
}
class CardGroup extends Component {
render() {
for (child in this.props.children) {
if (!this.props.children[child].props.isCard){
console.error("Warning CardGroup has a child which isn't a Card component");
}
}
return (
<div>{this.props.children}</div>
)
}
}
Checking for whether the Card component is indeed a Card component by using type
or displayName
is not safe as it may not work during production use as indicated here: https://github.com/facebook/react/issues/6167#issuecomment-191243709

- 1,307
- 15
- 12
-
1This seems to be the only way I can get this working in a **production build**. I have a component that clones its children while adding extra props only to those of a certain type. – Palisand Oct 13 '17 at 02:47
I made a custom PropType for this that I call equalTo
. You can use it like this...
class MyChildComponent extends React.Component { ... }
class MyParentComponent extends React.Component {
static propTypes = {
children: PropTypes.arrayOf(PropTypes.equalTo(MyChildComponent))
}
}
Now, MyParentComponent
only accepts children that are MyChildComponent
. You can check for html elements like this...
PropTypes.equalTo('h1')
PropTypes.equalTo('div')
PropTypes.equalTo('img')
...
Here is the implementation...
React.PropTypes.equalTo = function (component) {
return function validate(propValue, key, componentName, location, propFullName) {
const prop = propValue[key]
if (prop.type !== component) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
};
}
You could easily extend this to accept one of many possible types. Maybe something like...
React.PropTypes.equalToOneOf = function (arrayOfAcceptedComponents) {
...
}

- 8,208
- 3
- 35
- 41
static propTypes = {
children : (props, propName, componentName) => {
const prop = props[propName];
return React.Children
.toArray(prop)
.find(child => child.type !== Card) && new Error(`${componentName} only accepts "<Card />" elements`);
},
}

- 87,526
- 38
- 249
- 254
I published the package that allows to validate the types of React elements https://www.npmjs.com/package/react-element-proptypes :
const ElementPropTypes = require('react-element-proptypes');
const Modal = ({ header, items }) => (
<div>
<div>{header}</div>
<div>{items}</div>
</div>
);
Modal.propTypes = {
header: ElementPropTypes.elementOfType(Header).isRequired,
items: React.PropTypes.arrayOf(ElementPropTypes.elementOfType(Item))
};
// render Modal
React.render(
<Modal
header={<Header title="This is modal" />}
items={[
<Item/>,
<Item/>,
<Item/>
]}
/>,
rootElement
);

- 525
- 4
- 14
To validate correct children component i combine the use of react children foreach and the Custom validation proptypes, so at the end you can have the following:
HouseComponent.propTypes = {
children: PropTypes.oneOfType([(props, propName, componentName) => {
let error = null;
const validInputs = [
'Mother',
'Girlfried',
'Friends',
'Dogs'
];
// Validate the valid inputs components allowed.
React.Children.forEach(props[propName], (child) => {
if (!validInputs.includes(child.type.name)) {
error = new Error(componentName.concat(
' children should be one of the type:'
.concat(validInputs.toString())
));
}
});
return error;
}]).isRequired
};
As you can see is having and array with the name of the correct type.
On the other hand there is also a function called componentWithName from the airbnb/prop-types library that helps to have the same result. Here you can see more details
HouseComponent.propTypes = {
children: PropTypes.oneOfType([
componentWithName('SegmentedControl'),
componentWithName('FormText'),
componentWithName('FormTextarea'),
componentWithName('FormSelect')
]).isRequired
};
Hope this help some one :)

- 1,021
- 8
- 5
Considered multiple proposed approaches, but they all turned out to be either unreliable or overcomplicated to serve as a boilerplate. Settled on the following implementation.
class Card extends Component {
// ...
}
class CardGroup extends Component {
static propTypes = {
children: PropTypes.arrayOf(
(propValue, key, componentName) => (propValue[key].type !== Card)
? new Error(`${componentName} only accepts children of type ${Card.name}.`)
: null
)
}
// ...
}
Here're the key ideas:
- Utilize the built-in
PropTypes.arrayOf()
instead of looping over children - Check the child type via
propValue[key].type !== Card
in a custom validator - Use variable substitution
${Card.name}
to not hard-code the type name
Library react-element-proptypes implements this in ElementPropTypes.elementOfType()
:
import ElementPropTypes from "react-element-proptypes";
class CardGroup extends Component {
static propTypes = {
children: PropTypes.arrayOf(ElementPropTypes.elementOfType(Card))
}
// ...
}

- 116
- 4
An easy, production friendly check. At the top of your CardGroup component:
const cardType = (<Card />).type;
Then, when iterating over the children:
React.children.map(child => child.type === cardType ? child : null);
The nice thing about this check is that it will also work with library components/sub-components that don't expose the necessary classes to make an instanceof
check work.

- 668
- 6
- 9
-
1`(
).type` is equivalent to `Card`, i.e. the validation is simply `child.type === Card` – Sergii Shymko Jul 05 '22 at 22:09
Assert the type:
props.children.forEach(child =>
console.assert(
child.type.name == "CanvasItem",
"CanvasScroll can only have CanvasItem component as children."
)
)

- 4,079
- 2
- 28
- 37
-
1It's unreliable to iterate over the children prop assuming it's an array. It very well can be null or a single node. React provides handy utilities for handling children, such as React.Children.forEach(). See the official docs https://reactjs.org/docs/react-api.html#reactchildren – Sergii Shymko Mar 17 '21 at 01:27
Related to this post, I figured out a similar problem I had. I needed to throw an error if a child was one of many icons in a Tooltip component.
// icons/index.ts
export {default as AddIcon} from './AddIcon';
export {default as SubIcon} from './SubIcon';
...
// components/Tooltip.tsx
import { Children, cloneElement, isValidElement } from 'react';
import * as AllIcons from 'common/icons';
...
const Tooltip = ({children, ...rest}) => {
Children.forEach(children, child => {
// ** Inspired from this post
const reactNodeIsOfIconType = (node, allIcons) => {
const iconTypes = Object.values(allIcons);
return iconTypes.some(type => typeof node === 'object' && node !== null && node.type === type);
};
console.assert(!reactNodeIsOfIconType(child, AllIcons),'Use some other component instead...')
})
...
return Children.map(children, child => {
if (isValidElement(child) {
return cloneElement(child, ...rest);
}
return null;
});
}

- 1,458
- 2
- 20
- 39