2 functions that made my components responsive
A little bit of context
A few months ago I joined badi as a Frontend Engineer. When I started working on the product I noticed that Bootstrap was one of the main layout components used and more specifically Row
, Col
and Container
, which have a props interface that allows you to configure the components by plain properties or object styled properties for each media query available.
With that in mind, the Frontend team started working on the components library, which had tokens for the most used components. In my previous experience I found “Layout components” for spacing, alignment and arrangement super useful, so I decided to create two components:
Spacer
which was meant to manage spacing in units of 8px to increase design accuracy (inspired on my previous company's design system)Flex
which is a simple implementation around flex layout with some more sauce
At this time, we were happy with the result as we were moving from CSS modules to styled-components. Instead of having the repeated flex and spacing styling properties, we used descriptive components to be faster and have less detail overhead because the well-tested components were in charge of this.
The challenge
So far, so good… until we had a list of elements that had different layouts and spacings depending on the viewport. The fastest thing was to use our MatchMedia
component, which has render props patterns to show one or the other component on mount.
Since this component was only rendered after a call to the API, the flash of the wrong component wasn’t an issue.
But we could do better.
Solution(ish)
Remember the Bootstrap approach? The team was already familiar with the interface as we’ve already used our enum of media queries. So we thought: Why not tie this implementation into Spacer
and Flex
components?
So, the spacer would look something like this:
Easy peasy right?
And it will work if the passed props are correctly formatted. But again, we could do better.
The 2 functions
To conclude, the implementation above is too verbose and exposes the implementation of our media queries. What if we add another rule? Or if we have several responsive components? This doesn’t scale well…
We knew that:
- There will be base props, in the case of the
Spacer
, [top, right, bottom, left] - There will be media queries with the same shape that will allow more granular control, in our case, we have [sm, md, lg, xl]
We’ve already used media templates utility from Trick and Tips on styled components repository.
So we have our rules like:
Props validation
We needed to validate the shape of the prop for the responsive conditions so we can make sure that we have the expected behaviour without adding any dependency. I came up with this:
This will create an object of responsive props, with null values for the styled components. For example, the Spacer
component needs top, right, bottom and right props:
This is useful for the rules that will be passed to the styled component.
Responsive styling
Now that the props are correctly shaped, the next thing will be applying those to the component. To make it happen, I created a helper function that receives the styles function and returns the styling the given props, the styles for each breakpoint defined.
So finally, the styled component will look like this:
This allowed us to separate the possible breakpoints from the implementation of the styles for the component, making it flexible to implement to other components and easy to maintain since the media queries declaration is managed separately from the styling ones.
You can find the code in this gist.
Happy coding. ☕️
Originally published at https://dev.to on May 18, 2019.