React EQ

Have you ever wanted to add Element Queries to your React app? Rob shows how we added them to one of our recent React apps using React-EQ.

Over the past few years, element queries have been creeping into our projects. Much like media queries, element queries allow us to style elements based on size. The difference, however, is that it’s not the size of the browser that determines these changes, it’s the size of the containing element. Imagine you have a list of top movies for an actor. In the main body section of the page, each movie needs to be depicted using an image to represent that movie. However, this same component needs to be able to display as a text list of the movie names in a sidebar, where showing each image would take up too much space. Wouldn’t it be nice to create one component that was able to modify itself to work in multiple contexts?

Recently, while working on a large React app, we had a need to display the same chart in two different places on the page, and it needed to behave differently in each place based on its size. Our solution to this was to use an element query. There are a few popular element query libraries available. We really like SnugUg’s eq.js for many projects, and it ships with a nice SASS helper for writing your element queries. However, for this project, because of the difficulties of modifying the DOM nodes that React controls, we looked for a purpose built React element query component. With this in mind, we started using react-element-query, which worked well, but it works by adding class names to the container element, which was undesirable. At the same time, other (non-React) parts of this project were using eq.js, which uses the data attribute [data-eq-state] on the container element. This meant that we had two different methods for accomplishing the same task.

The Solution

Enter react-eq, a React component that gives you element queries using the same data attribute API that eq.js uses. With this in place we can define the sizes at which we want things to change, such as:

const queries = {
  medium: ‘400px’,
  large: ‘600px`
}
<ElementQuery queries=queries>
  <Movies />
</ElementQuery>

With this, react-eq will update the child (<Movies />) based on its size: Less than 400px it will have no data-eq-state attribute (text list of movies); Greater than or equal to 400px it will have data-eq-state=”medium” (images for movies); Greater than or equal to 600px it will have data-eq-state=”small large” (larger images for each movie). By targeting these data-attributes in your component’s CSS, you can make whatever style adjustments you need, for each container size.

.movie {
  display: none;
}
.movie[data-eq-state~=medium] {
  display: block;
  grid-template-columns: repeat(2, 1fr);
  ...
}

.movie[data-eq-state~=large] {
  grid-template-columns: repeat(4, 1fr);
  ...
}

Using react-eq gave us a really nice way to allow our components to flex to any size depending on where they might show up in our app. This is also great when you’re delivering components to third-party systems where you don’t have much control over how much of the screen they will take up. This helps to ensure that your components always look good. And when they look good, you look good.

Feel free to check it out and use it in your own projects.