Responsive Header in React (feat. CSS Grid Layout, React Hooks and React Transition Group)

Sid Bentifraouine
6 min readMay 5, 2019

--

This tutorial is for React Beginners who want to learn and play around with React Hooks, CSS Grid Layout and React Transition Group.

The implementation of this use case be done in totally different ways so that you might find it not adapted to you, but “Hey, we are here to learn ❤️.”

Let’s go!

Project Setup

If you do not have an up and running React project then you can go this way:

npx create-react-app my-app
cd my-app
npm start

Project Structure

Everything we write in this tutorial will be inside src/ folder (we will omit other stuff for this tutorial, to stay focused on the Header component and its usage):

src/
├── assets/
├── components/
│ ├── Header.css
│ └── Header.js
├── styles.css
└── index.js
  • Create a components/ folder and then
  • Create Header.jsand Header.cssfiles (Note that we could have used aCSS in JS library for styling, but this tutorial is targeting true beginners, so maybe next time though)

Header Component

The header is a Stateless Component, and it will use React Hooks for its state management.

Let us structure our component with CSS Grid Layout:

Let us discuss what is happening above:

  • display: gridgenerates a Block Level Grid
  • grid-template-areas: ‘logo nav’ creates a Grid Template by referencing by “name” the Grid Areas that we will name below

We also need to structure the Nav:

  • grid-area: nav Gives the .Nav a name so it can be referenced by `grid-template-areas in the parent element
  • display: grid Generates also a Block Level Grid (You can nest everything as you want to)
  • grid-template-columns: repeat(4, auto) or grid-template-columns: auto auto auto auto. both syntaxes are the same, they will create a Grid Column Template, which will split our grid into four columns. Each column will be as wide as the element (auto)
  • align-items: center Will make direct children elements centered along the Column Axis
  • justify-items: Will make direct children elements centered along the Row Axis, here we have only one row by default.

One finished, this should look like this:

It seems right for now, but how about the responsive part?

Yup! the header sucks on small screens, so let us dive into the next part in which we will learn how to fix it.

Responsiveness

Let us start by using a simple Media Query:

We will have a Burger that will be visible only if we are on Small Screens.

So when the Screen Size matches the Media Query, the following will happen:

  • Header: by adding grid-template-areas: "logo burger" "nav nav" , we will change the Template Area to have One Row which will be divided into Two Columns, then A Second Row which will be filled by the Nav Area
  • Nav: grid-template-rows: repeat(4, auto) will set Four Rows, grid-row-gap will add space between each Row
  • Burger: display our burger which was set to none for large screens

With all Cosmetic Styles that you’ll find in the Github Repo and also in the CodeSandBox, this should look like this on Small Screens:

Toggling with React Hooks

Here are the big lines of what we should do to manage our Header visibility:

  • We have imported useState from react
  • Inside our Stateless Functional Component: We will use useState(<initial_value>), so it will return for us an array. Its First Element is the Stateful Value which will be set to true, and the Second Element is its Updater Function. And we will recover them by using the ES6 (or ES2015) Destructuring Syntax
  • The toggleNav The Function will handle our Burger Button click and set the isNavVisible Stateful Value.
  • Then we will show <nav /> only if the isNavVisible Value is set to true

It looks good for now, but we face a problem? Can you see it?

  • First: the first time we are on a Small Screen, the Nav is visible
  • Second: if we hide the Nav by using the Burger Button, it will be hidden even if we go on Larger Mode

See by yourself:

How to fix it?

This case is another pretext to use a React Hooks feature again 😅!

useEffect Hook for Hooking on React Lifecycles

useEffect is like componentDidMount, componentDidUpdate, and componentWillUnmount combined.

Our usage will concern only the Component Mounting Part so we can listen to Screen Size changes.

Let us first add a isSmallScreen Stateful Value that will reflect whether the screen matches our Media Query or not.

Then let us use useEffect :

The useEffect runs every time the component is rendered and performs DOM updates. So by giving the first argument, React will run the Callback all those times.

The second argument is an Array of the values that are the Condition to run the Callback, like: “If of on these values changes, then run my Callback.”

So React will run the Callback when the component renders the first time, and then it will run it only if one of the values changes.

By giving is an Empty Array, we are telling React that we need it to run only once: Component Mounting.

The matchMedia lets us know whether the Media Query is matched with matches property.

Now, we need to update our conditional <nav /> rendering to this below:

Animate this!

Of course, you can do this in plain CSS but let’s demonstrate the usage of an excellent library that simplifies Animations when using React: react-transition-group.

yarn add react-transition-group
# or
npm i react-transition-group

Here is an example of what you can do with it:

We just imported it. We wrapped the <nav /> with <CSSTransition /> :

  • in : Show or Not the component
  • timemout: Duration of the transition in ms
  • unmoutOnExit : Unmount the component after it finishes exiting
  • classNames : The animation prefix for each entering, exiting stage

Now, let’s suffix each animation for each stage (enter, enter-active, exit, exit-active)

Final Result

Thank you for reading this article 🙏. Note that this is my first article, and I am pretty sure that it’s far away from being perfect, so let me know if you liked it or not, your feedback is valuable to me! ❤️

Github: https://github.com/sidbentifraouine/react-responsive-animated-header

--

--

Sid Bentifraouine

I’m a Frontend Engineer who loves learning and sharing new things with love 👨‍💻❤️