Media query templates in styled components

December 03, 2018

Of late, the ‘CSS in JS’ approach to organizing stylesheets in a project has become ever more popular in the React ecosystem. I think there are two main reasons for this:

  • In a world where everything is a component, coupling styles with view code makes each component more manageable and sharable between projects.
  • The ability to use variables, especially by interpolating them with Javascript template literals, allows for an even greater amount of flexibility than what you get using a CSS preprocessor like SASS or LESS.

That being said, most people seem to favor one of two approaches to implementing CSS in JS: styled-components, and emotion. Both are similar in many respects, but most of my experience has been with the larger of the two projects, styled components.

In this post, I’ll touch on what I think is one of the neatest parts of how styled components can be used: media templates! Here's what the styled components docs have to say about it:

Since media queries are long and are often repeated throughout an application, it can be useful to create a template for them. Due to the functional nature of JavaScript, you can easily define your own tagged template literal to wrap styles in media queries.

Let me show you how I’m using this approach in this site:

// media.js
import { css } from 'styled-components'
const sizes = {
// default styles written mobile-first assuming 320px width
mbl: 375,
tab: 700,
desk: 990,
deskL: 1200,
}
// Iterate through the sizes and create a media template
const media = Object.keys(sizes).reduce((acc, label) => {
acc[label] = (...args) => css`
@media (min-width: ${sizes[label] / 16}em) {
${css(...args)};
}
`
return acc
}, {})
export default media

I tuck the above code away in the utils directory, and then whenever I need to use a media query in any component throughout the project I can import and use it like so:

// textXL.js
import styled from 'styled-components'
import { dark } from '../utils/colors'
import media from '../utils/media'
const TextXL = styled.h1`
font-family: Quincy, serif;
font-weight: normal;
font-size: 44px;
color: ${dark};
line-height: 52px;
padding: ${props => (props.padding ? props.padding : `auto`)};
margin: ${props => (props.margin ? props.margin : `auto`)};
text-align: ${props => (props.center ? `center` : `left`)};
${media.tab`
font-size: 48px;
line-height: 58px;
`};
`
export default TextXL
view raw scMediaQueryUsage.js hosted with ❤ by GitHub

And that’s it! There are many more exciting aspects of how to extend styled components, but of all of them, this solution to media queries is by far the most elegant and unique in my view. Hope you enjoy using this as much as I do, and happy querying!

Thanks for reading ❤️

If you're jazzed about this post, feel free to tweet this article 🐦

If I missed something, please do drop me a message and I'll fix it 🔨

Otherwise, read more articles! ✍️