How to create responsive UI with styled-components

There are several approaches on creating responsive web apps with ReactJS. Apart from using whole frameworks like Bootstrap, I wanted to create a responsive grid view with styled-components, which was amazingly painless.

Photo by Oliur Rahman on Unsplash

Now that I built an actual web app (admittedly, a tiny one) with ReactJS and styled-components, I wondered how easy it would be to create something more responsive. More precisely, I wondered how one would create a responsive page layout like it is easily done with Bootstrap, just to name an example. And that’s what we are going to build along this article, a simple grid view which allows us to split a web site into columns which will be stacked as soon as it is opened from a phone or tablet.

Until this point, whenever I built a responsive web page layout, I always relied on Bootstrap, or react-bootstrap, when working with ReactJS. Why? Because I found it easy to use and it made development a little bit faster.

But not this time. So I had a look on w3schools tutorial on building a responsive grid view to find out what happens behind the curtains of all those fancy libraries:

How does a responsive grid view work?

First of all, I want to give a short introduction how responsive grid views work. If you already know this, please feel free to skip this section.

Usually such grids have twelve columns which have a total width of 100 percent. Depending on the website’s layout you may not need all of them, so it should be possible to merge some columns together to get a bigger one. What really happens in the background is that there is a bunch of div tags with equal width floating to the left, so they appear in a row.

.column {
width: 8.33%;
float: left;
}

EDIT: As stated by Mauro Lionel Ocorso and Jean Duthon it is also possible to use flexbox instead of float: left;. However there might be some compatibility issues if you want to support older browsers also. Thank you guys for pointing this out!

A grid with twelve columns

Since the whole grid has a width of 100 percent, each of the columns are exactly 8.33% wide. Now let’s say we want a bigger column at the beginning of the grid, in the size of three columns or 25 percent of the screen.

The first column spans across the first three columns

In the picture above, you can see the first column spanning across three columns, which caused the second and third column to disappear. What really happened is not a real column span. The first column got a width of 25 percent and columns 2 and 3 were deleted now that they are not needed anymore.

To achieve this, some changes have to be made. Instead of having one CSS-class for each column, there is one for each possible column span. This is also reflected in the class names I used: While col-1 spans across one column, col-3 spans across three and col-12 would have a width of 100 percent.

[class*="col-"] {
float: left;
}
.col-1{
width: 8.33%;
}
.col-2 {...}
.col-3{
width: 25%;
}
[...]

The only thing missing now, is how we get to stack the columns as soon as we view our page from a smaller device. This can be achieved by using media queries (learn more about them here).

The columns should stack vertically when viewed from a small device

Let’s say we want to stack the columns as soon as the width is smaller than 768px.

[class*="col-"] {
/*Mobile first: set the width to 100% by default*/
width: 100%;
}
@media only screen and (min-width: 768px) {
/* For everything bigger than 768px */
.col-1{
width: 8.33%;
}
  .col-2 {...}
  .col-3{
width: 25%;
}
}
[...]

First of all, I set the initial width of all columns to 100 percent. Because that is how it should look like on a smaller screen, it also improves the performance of the page display for them. By setting the width to 100 percent, the columns automatically stack vertically, so yep, there is not much more to do.

The second important thing is the @media rule I added: As soon as the width exceeds 768px, the overall widths from the last example are used.

Now having covered the basics, let’s see, how this is done with React and styled-components!

Creating the basic grid view with styled-components

As a starter, we will build the exact same grid, like I covered in the last section:

  • It will have twelve possible columns
  • A column can span across the width of 1–12 columns.
  • If the total width is smaller than 768px, all of the columns will stack vertically.

In the following screenshot you will see, that I created a component called Row which is needed to clear the float after the columns. Then I added a Column component, which has by default float: left set, and a width of 100% (mobile first, you remember?).

But have a look on your own:

Our grid built with styled-components

The Column component takes a prop span which represents the amount of columns to span across. If this prop is set, we calculate the desired width in percent. If no column span is set, we default to 8.33 percent, which is the default width for a column span of 1.

Extending the grid: Different breakpoints!

Taking Bootstrap as an example, we want to have the possibility to define different column spans for different viewports. This would give us the possibility to use different column spans on different screen sizes.

To achieve this, Column will no longer take a span prop. Instead there will be one for each breakpoint:

  • xs for screen sizes up to 768px
  • sm for sizes up to 992px
  • md for sizes up to 1200
  • lg for everything bigger than that
Our new Column component

So what did we do here? Since we do not have a fallback width for column spans bigger than xs we no longer calculate the value of the width, but the whole text instead.

For example: If you set a column span of 6 for md, you will get width: 50%; on medium devices. if you do not set a column span for md and the screen width exceeds 992px, we will just not set any width. This way the column gets always the width for the next smaller set column span, or 100% if nothing is set.

Now let’s see how it works:

The above example should render a grid with two columns.

Extra small screens (<768px)
On extra small screens, the first column takes the whole width, while column number 2 is shifted to the next row.

Our example rendered on an extra small screen

Small screens (>768px) 
The first column should span across 6 columns and should therefore get a width of 50 percent. In this case the second column does not have a column span for small screens set, so the width of the next smallest break point is assigned: 50 percent.

Small screen — If no column span for a certain screen size is set, the next smaller one is assigned.

Medium screens (>992px) 
This should be easy: The first column spans across 8 columns (66.66 percent) and the second one spans across 4 columns (33.33 percent)

Medium screen

Since we did not set a column span for large screens, both columns look the same like they look on medium screens.

Conclusion

What we built here was an example of a responsive grid with styled-components with basic functionality. You could possibly extend the components to support more styling like margins, paddings or borders, just to name a few.

I think the most advanced responsive grid view I could find in my research for this article, is grid-styled from Brent Jackson. It even allows you to set different font sizes for four different breakpoints and much more. For this article however, I tried to cover the basics of responsive grids and how to build one. And what I really liked was the fact how easy it was to consider the different breakpoints since we can use real CSS. I know, there are several alternatives out there and I already had a look on some of them. But in terms of using media queries most blog posts recommend using libraries like react-responsive or react-responsive-mixin which may not be bad, but just did not feel right to me.


Thank you for reading this article. I hope I could provide you with some useful information. If so, I would he happy if you would recommend this post and click the little heart ♥ button so more people can see this.

I’m always happy to receive feedback! So if there are questions or you want to add something here, please leave a comment, or catch me up on Twitter.

NEW: Subscribe to my mailing list so you never miss a new post again! I’m delivering my articles and cool stuff that I want to share with you on a weekly basis directly into your inbox.