Compound Component Design Pattern in React

Avoid prop drilling, and write expressive components with implicit state sharing

Photo by Danist Soh on Unsplash

What are Compound Components?

Compound components are a React pattern that provides an expressive and flexible way for a parent component to communicate with its children, while expressively separating logic and UI.

In compound components instead of passing state through props, we pass elements as children to a parent element.

So what are we actually talking about:

<select name="places" id="places-select">
<option value="paris">Paris</option>
<option value="boston">Boston</option>
<option value="london">London</option>
</select>

In HTML, we can pass options to a <select> element as children. The select element manages the state, and we clearly see what elements are passed as options to the select.

In React we can do a very similar thing, pass children as elements while the parent manages implicit state.

Implementing Compound Component pattern in React

Let’s start with a simple Card component. I want to render links on the card, and if there are a lot of links, limit the amount shown, and have a show more show less toggle to expand or collapse the card for displaying links.

Here’s what my simple component looks like:

My component takes in content as props, and it renders a <CardItem /> for each item in my content object.

The component starts in a collapsed state, which causes it to render only three links (I’ve set a LIMIT of three). But I also have a toggle function, that if show more is clicked, the collapsed state changes and all links are rendered — show more becoming show less.

Easy, right? But what if I have multiple use cases for this component. What if I want to reuse this functionality of toggling show more/less but each time on different cards with different UI.

With my current component I don’t have the flexibility I would need to do this. My functionality is coupled with the UI.

If I were to need a different component from my <CardItem /> for the links, I would have to pass a props to control for the different cases, or possibly even create a new component if the amount of props became too complex.

This is where our compound component comes in:

Here we start with a Card component, manage an isCollapsed state like in our previous component, but now we’re storing the value using Context API.

We also use two functions for expand and collapse, and stick those in the card context as well. The only props our component takes in is children, and we render the children inside of our context provider inside of a card div.

Next, I want to create a component for the content of my card, and a way to control what elements I’m using for expanding and collapsing.

CardContent is mapping over its children and controlling how many children (in this case links) are being rendered.

The Expand and Collapse components are using the expand and collapse functions from inside our Card component, along with the isCollapsed boolean value, extracted from our CardContext.

Both functions are then returning an element using React’s cloneElement() method which will clone whatever element is passed as a child to the component and return it with the given configuration. In this case, an onClick with a specified function. (Read more about React’s clone element here.)

Finally, we export our Card component with all its components.

This technique is super explicit, giving the user of the component a clear look into what each method is doing.

Now we can finally use our component!

Inside of Card.CardContent, Card.Expand and Card.Collapse, we can put any element as children and they will always have the functionality given to the component.

This gives the flexibility to use this card’s collapse and expand functionality with literally any component, its completely decoupled!

Conclusion

Reusability is key in React, and knowing what tools are at your hands can make developing more fun and a lot easier.

I hope this tutorial gave some insight into how to use compound components and the value they can add to a project:)

Make sure to check out the CodeSandbox of this project here.


Compound Component Design Pattern in React was originally published in Better Programming on Medium, where people are continuing the conversation by highlighting and responding to this story.

0
(Visited 8 times, 1 visits today)