Find & Filter React Children By Type (HTML Elements)
Discover the type of your React children — HTML Element Edition
Article Update:
I’ve decided rewrite these utils from the ground up, add a bunch of new ones (including deep/recursive searching) and publish an NPM package for all to consume:
This article will discuss finding and filtering React children by type as it pertains to core HTML Element (JSX Intrinsic Element) children like divs, spans, etc. If you are looking at finding and filtering custom component types, please see my other article:
I also discuss in that article several reasons why you would want to be able to control your children by type. I won’t be reviewing those here other than our hypothetical example so please head over to to my other article if you’re interested in the “why”.
The Scenario
Let’s imagine a hypothetical example that we can use to do some finding and filtering.
Let’s say we are tasked with creating an EmployeeInfo
component which we expect to take an <img />
element as a child that will be the avatar for the employee. And let’s further say that the <img />
child is the only child we expect to receive. Anything else is considered something we don’t want.
We want to consume it like this:
<EmployeeInfo
firstName="Beardy"
lastName="McBeardison"
title="Sr. Lumberjack">
<img src="bmcbeardison.jpg" />
</EmployeeInfo>
And render like this:
Here is our first iteration of the component:
The situation we find ourselves in is that children can literally be anything.
I actually do mean literally!
<EmployeeInfo
firstName="Beardy"
lastName="McBeardison"
title="Sr. Lumberjack">
<div>Anything!</div>
</EmployeeInfo>
That might be OK in some contexts but, in our situation, this won’t work. We’re expecting an image.
In addition to that, the user can pass in an image and anything at the same time:
<EmployeeInfo
firstName="Beardy"
lastName="McBeardison"
title="Sr. Lumberjack">
<img
className="employee-image"
src={portrait}
alt="Visual approximation of Beardy" />
<div>Image + Anything!</div>
</EmployeeInfo>
That’s definitely not what we intended.
Gimmie the secret sauce, already!
React components have a type
property that you can reliably use to your advantage for core HTML Element components/children.
Do a console.log(children)
and see for yourself:
WARNING and CAUTION!
type
is reliable in development and production builds for HTML Element components only. Don’t try to use this for custom components or you may have regrets–if not in development, possibly in production. For custom components, see my article that I referenced at the top.
Now that we’ve gotten that out of the way…
Remember that our goal is to have the image tag only. We can create some utils to make our lives easier:
We’ve added a getChildrenByType
util function that takes in children
and an array of string types
that we want to find. It will return the first matching type.
You’ll notice in the typeOfComponent
function that it’s doing a check for __TYPE
. This is for custom components. Please see my article linked at the top for more information on that. For our purposes in finding and filtering by HTML Elements, we’re going to be looking at type
.
Now we can refactor our component:
What we’ve done here is consume our util function and tell it that we want it to fetch us the first img
element of our children. If none is found, it will return undefined and a default image will be displayed in its place. Any other children that aren’t images, will be removed.
If we revisit our previous examples:
<EmployeeInfo
firstName="Beardy"
lastName="McBeardison"
title="Sr. Lumberjack">
<div>Anything!</div>
</EmployeeInfo>
And:
<EmployeeInfo
firstName="Beardy"
lastName="McBeardison"
title="Sr. Lumberjack">
<img
className="employee-image"
src={portrait}
alt="Visual approximation of Beardy" />
<div>Image + Anything!</div>
</EmployeeInfo>
We did it!
Let’s suppose that we have a custom component called EmployeeImage
that was built using the type pattern that I outline in my other article and we want EmployeeInfo
to be able to accept an <img>
or an EmployeeImage
.
We can definitely do that. All we need to do is change the types that we’re filtering by adding EmployeeImage
to the list:
getChildByType(children, ['img', 'EmployeeImage'])
This function says, “Get the first child that is either an img
or an EmployeeImage
.” The order of the items in the array doesn’t matter. It will return the first match that it finds.
One other thing I want to point out about the util is that it’s also capable of finding React Fragments no matter if they are <React.Fragment>
or <>
. You simply pass into your types array ['react.fragment']
.
Awesome! Do you have any other helpful utils?
Yes! To recap the article update posted at the top, I’ve published an NPM package that has these utils re-engineered to handle additional situations and offer more options to give you flexibility. There are also many additional utils that we didn’t discuss in this article:
Here is a list of the utils currently available in react-nanny
:
getChild
— Gets first child by specified predicategetChildDeep
— Gets first child by specified predicate (deep search)getChildByType
— Gets first child by specified typegetChildByTypeDeep
— Gets first child by specified type (deep search)getChildren
— Gets all children by specified predicategetChildrenDeep
— Gets all children by specified predicate (deep search)getChildrenByType
— Gets all children by specified typegetChildrenByTypeDeep
— Gets all children by specified type (deep search)noEmptyChildrenDeep
— Ensure that there is some level of content and not just a bunch of empty divs, spans, etc (deep search)removeChildren
— Removes all children by specified predicateremoveChildrenDeep
— Removes all children by specified predicate (deep search)removeChildrenByType
— Removes all children by specified typeremoveChildrenByTypeDeep
— Removes all children by specified type (deep search)typeOfComponent
— Gets the string type of the component if defined by a prop, the string type of the core html (JSX Intrinsic) element, or the function type
But wait! There’s more…
Now you can find and filter HTML Element components as well as React Fragments. If you want to do this same kind of thing with custom components, please head over to my other article: