Responsive Header in React
Tags: react, javascript, beginners
Published: 2020-10-01 21:28:24

[On Netlify](https://simpleresponsiveheader.netlify.app/) => [Code](https://github.com/hajarNasr/responsive-header-in-react)

I used to think that making a responsive header in React would be complicated but once I started to implement it, it was much simpler than I'd thought.

I guess the first thing to think of when creating a responsive header is the way to measure the screen whenever it resizes. And fortunately for us, javascript provides an eventListener for exactly that purpose, the `resize` eventListener.

Let's see how we can take advantage of that eventListener to achieve our goal of making a responsive header.

```javascript
// CustomHooks.js
import { useEffect, useState } from 'react';

export const useWindowWidthAndHeight = ()=>{
    // 1- Get the size of window 
    let windowInnerSize = [window.innerWidth, window.innerHeight];

    // 2- Define the state variable windowSize and pass windowInnerSize as its initial value
    let [ windowSize, setWidowSize ] = useState(windowInnerSize);

    useEffect(()=>{
        const changeWindowSize = ()=>{
            setWidowSize([window.innerWidth, window.innerHeight]);
        }
        /* 3- add a 'resize' eventListener to window so that whenever 
the size of window changes the state variable windowSize changes and the component re-renders */
        window.addEventListener("resize", changeWindowSize);

        // 4- cleanup the 'resize' eventListener
        return ()=> window.removeEventListener('resize', changeWindowSize);
    }, []);
    // 5- return the window size
    return windowSize;
}
```
Here, we create a custom hook called `useWindowWidthAndHeight`. 

Inside `useWindowWidthAndHeight`: 
**First**, we create the `windowInnerSize` variable to store the current width and height of `window`. 
**Second**, we use `windowInnerSize` as the initial value for the state variable `windowSize` that we created using the `useState` Hook.
**Third**, we declare a `useEffect` Hook to add a `resize`eventListner so that when a window `resize` happens, `changeWindowSize()`changes `windowSize` to the new measured `width` and `height` of the screen. 
**Finally**, we return the latest measured width and height of `window`.

Now, let's create a header.
```javascript
// Header.js
import React from 'react';
import Navbar from './Navbar';
import { Link } from 'react-scroll'; // react-scroll is a library for scrolling in React
import SmallScreensNavbar from './SmallScreensNavbar';
import { useWindowWidthAndHeight } from './CustomHooks';

const Header = () =>{
    // use our custom hook to get the the window size
    const [width, height] = useWindowWidthAndHeight();
    return(
        <header>
            <div className="header-inner">
                <Link to="Home" 
                      smooth={true} 
                      className="logo nav-link">
                      RH
                </Link>
                {/*if the width of the window is bigger than 1000px use <Navebar/>,
                   else user <SmallScreensNavbar/>*/}
                { width > 1000 ?
                <Navbar navClass="nav-big"
                        linkClassName="nav-big-link"/>
                :
                <SmallScreensNavbar navClass="nav-small"
                                    linkClassName = "nav-small-link"
                />
                } 
            </div>
        </header>
    )
}

export default Header;
```
Now, we need to create two navbar components, one for the screens with widths bigger than 1000px and another for smaller screens.

```javascript
//Navbar.js
import React from 'react';
import { Link } from 'react-scroll';

const Navbar = ({navClass, linkClassName}) =>(
    <NavComponent navClass={navClass}
                  linkClassName = {linkClassName}
    />
);

export const NavComponent = ({onClick, navClass, linkClassName})=>(
  <nav className={navClass}>
      {["Projects", "About", "Contact", "Footer"].map(section=>
        <Link to={section}
              smooth={true}
              className={linkClassName}
              onClick={onClick}>
            {section}
        </Link>
      )}
  </nav>
)
export default Navbar;
```
And for smaller screens:

```javascript
//SmallScreensNavbar.js
import React, { useState } from 'react';
import { NavComponent } from './Navbar';

const SmallScreensNavbar = () =>{
    // declare 'translate' as a state variable
    let [translate, setTranslate ] = useState(true);
    return(
        <div> 
             <button className="hamburger-btn"
                     onClick= {()=> setTranslate(!translate)}>  {/* toggle translate */}
                  {/* change the btn text based on whether translate is true or false */} 
                 {translate?<span>&#9776;</span>:<span>&times;</span>}
             </button>
             {/*hide and show the sidebar list based on whether translate is true or false*/}
             <div id="sidebar-list" className={`${translate? "addTransiton": "removeTransition"}`}>
                <NavComponent
                    navClass="nav-small"
                    linkClassName = "nav-small-link"
                    onClick = {()=>setTranslate(true)}  //set translate to true to hide the sidebar list
                />
             </div>
        </div>
    )
}
export default SmallScreensNavbar;
```
Now, for this to work we need to add the CSS:
```css
header{
    position: fixed;
    top: 0;
    height: 70px;
    background-color: rgb(197, 178, 178);
    width: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    box-shadow: 1px 1px 1px 1px rgba(116, 110, 110, 0.199);
}
.header-inner{
    width: 90%;
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.hamburger-btn{
    font-size: 1.3rem;
    position: absolute;
    bottom: 0;
    width: 40px;
    height: 35px;
    right: 30px;
    outline: none;
    background-color: rgb(134, 125, 125);
    color: whitesmoke;
}
.addTransiton{
    transform: translateX(170px);
    transition: transform 0.5s ease-in-out;
}
.removeTransition{
    transform: translateX(20px);
    transition: transform 0.5s ease-in-out;
}

#sidebar-list{
    background-color: rgb(134, 125, 125);
    height: 90vh;
    width: 170px;
    position: absolute;
    z-index: 2000;
    right: 0;
    top: 0;
    margin-top: 70px;
}
.nav-big{
    list-style: none;
    display: flex;
    justify-content: space-around;
    width: 70%;
    font-weight: bold;
}

.nav-big-link{
   cursor: pointer;
   color: white;
   text-decoration: none !important;
}

.nav-small{
    display: flex;
    flex-direction: column;
    text-align: center;
    justify-content: space-around;
    margin: auto;
    height: 40%;
    margin-top: 50px;
    width: 80%;
}
.nav-small-link{
    cursor: pointer;
    color: whitesmoke;
    padding-bottom: 5px;
}

```

And things should be working now.
Thank you so much for reading. :)

**References:**
[Stackoverflow](http://stackoverflow.com/) to find out how to measure the screen's width and height.