_kud's tech blog

How to handle responsive design in React

Also works with Next.js

Hello and welcome in 2021 🥳. I didn't write for ages, glad to see you again.

Okay, alright. Today, let's talk about Responsive Web Design (also known as rwd) in a React context. (This also works with Next.js). As you may say, the most obvious way could be to use @media in a CSS file, which makes totally sense as it is how it works.

But I'm not here for that. I'm here to show you different ways to handle Responsive Design which can be really helpful when you want to change more than only the CSS.

For that, we will use contra/react-responsive which is really good. You have multiple libs to handle our subject but this one also works with SSR (that's why I find it interesting for Next.js) and has a onChange trigger which can be useful.

So, stop talking, let's see my solution.

Installation

1$ npm install react-responsive

Reference file

Let's create our main file. This is where you set all your responsive cases.

1// ./media-queries.js
2
3const MQ = {
4 "--tablet": "(max-width: 1279px)",
5 "--desktop": "(min-width: 1280px)",
6}
7
8export default MQ

It will be our reference.

Hooks

Time to create our custom hooks.

1// ./src/hooks/media-queries.js
2
3import { useMediaQuery } from "react-responsive"
4
5import MQ from "media-queries"
6
7export const useDesktopMediaQuery = () =>
8 useMediaQuery({ query: MQ["--desktop"] })
9
10export const useTabletMediaQuery = () =>
11 useMediaQuery({ query: MQ["--tablet"] })

Components

Now, our components.

1// ./src/components/MediaQueries/index.js
2
3import { useDesktopMediaQuery, useTabletMediaQuery } from "hooks/media-queries"
4
5export const Desktop = ({ children }) => {
6 const isDesktop = useDesktopMediaQuery()
7
8 return isDesktop ? children : null
9}
10
11export const Tablet = ({ children }) => {
12 const isTablet = useTabletMediaQuery()
13
14 return isTablet ? children : null
15}

Usage

That's great! As you can see, now we've got our references in one file, also some hooks if needed, and the components if you think it is easier to read. I assume here you've got @emotion/styled or styled-components for a certain part of this code.

Let's see how we can use it.

1// ./src/pages/index.js
2
3import MQ from "media-queries"
4
5import { useDesktopMediaQuery, useTabletMediaQuery } from "hooks/media-queries"
6
7import { Desktop, Tablet } from "components/MediaQueries"
8
9const Root = styled.div`
10 {/* direct way */}
11 @media ${MQ["--desktop"]} {
12 {...}
13 }
14
15 @media ${MQ["--tablet"]} {
16 {...}
17 }
18`
19
20const IndexPage = () => {
21 // hook way
22 const isDesktop = useDesktopMediaQuery()
23 const isTablet = useTabletMediaQuery()
24
25 if (isDesktop) {
26 alert("Wow! Nice display screen!")
27 }
28
29 return (
30 <Root>
31 {/* component way */}
32 <Desktop>
33 <LargeMap />
34 </Desktop>
35
36 <Tablet>
37 <BurgerIcon />
38 </Tablet>
39
40 <Button fullWidth={isTablet}>{`My button`}</Button>
41 </Root>
42 )
43}

This is perfect! Now, You have different ways depending on your context (jsx, style, etc), really easy to read.

Enjoy.