Hamburger Navbar Animation in React
Tags: react, webdev, javascript, tutorial
Published: 2020-06-12 18:32:32

<em>Summary</em>: Unlike in jQuery, you can't toggle classes on your HTML elements directly because React uses JSX. You need to use <a href="https://reactjs.org/docs/refs-and-the-dom.html">React Refs</a> in order to toggle classes to your JSX elements in order to animate them. That's the process I intend to walk the reader through in this article.
In the <a href="#first_part">first part</a> of the article, I show how it's done in regular HTML and VanillaJS. The <a href="#second_part">second part</a> shows how to do the exact same thing, but in React. And finally I've included a gif of the <a href="#product">end product</a>.
<hr>

Let's face it, imperative animations in React is not intuitive. You can't simply select a HTML tag and add an event listener to it. Or can you? Not really. But there's a work around.

I came across YouTube video by <a href="https://www.youtube.com/channel/UClb90NQQcskPUGDIXsQEz5Q">Dev Ed</a> where he shows a sweet and minimal hamburger <a href="https://youtu.be/H4MkGzoACpQ">navbar animation</a>. I wanted to add something like it to a site I was working on. But the problem I faced was that Ed (the YouTube guy) implemented his animation with Javascript but my project was built in React. I could steal his CSS but I couldn't quite steal his Javascript.

I'm not going to bore you with my quest of finding a work around (although I'd love to share the story with you in another post if you're interested in it🙃). Let's get down to the how-tos.

First let me show you how Ed did it. If you want to go straight to the React way of doing it, click <a href="#second_part">here</a>. I've extracted some parts of his HTML, CSS, and Javascript. If you don't want to look through he code, skip down below for a brief description of what he does.
<a id='first_part'></a>
Here's a part of Ed's HTML.

```html
<div class="menu">
  <div class="line"></div>
  <div class="line"></div>
  <div class="line"></div>
</div>

<ul className="nav-links">
  <li>Home</li>
  <li>Projects</li>
  <li>About</li>
</ul>
```

Here's a part of his CSS.

```css
nav {
  background-color: #469fdf;
  height: 15vh;
  width: 100%;
  display: flex;
  align-items: center;
  padding: 5px;
  position: relative;
}

.nav-links {
  display: flex;
  list-style: none;
  width: 50%;
  height: 100%;
  justify-content: space-around;
  align-items: center;
  margin-left: auto;
}

@media screen and (max-width: 768px) {
  .line {
    width: 30px;
    height: 3px;
    background: white;
    margin: 5px;
  }

  nav {
    position: relative;
  }

  .menu {
    position: absolute;
    cursor: pointer;
    right: 5%;
    top: 50%;
    transform: translate(-5%, -50%);
    z-index: 1;
  }

  .nav-links {
    position: fixed;
    top: 0;
    background: #1484f5;
    height: 100vh;
    width: 100%;
    flex-direction: column;
    clip-path: circle(100px at 90% -30%);
    -webkit-clip-path: circle(100px at 90% -30%);
    transition: all 1s ease-out;
  }

  .nav-links.open {
    clip-path: circle(1000px);
    -webkit-clip-path: circle(1000px);
  }
}

.nav-links li {
  color: white;
}
```

And finally, here's the magical javascript that Ed used to make the gorgeous animation.
```javascript
const menu = document.querySelector(".menu");
const navLinks = document.querySelector(".nav-links");
const links = document.querySelector(".nav-links li");

menu.addEventListener("click", () => {
  navLinks.classList.toggle("open");
});

```

What he did is he created a navbar, created a hamburger menu within it using three divs that made three straight lines, added some nav-links, and then masked them using CSS. And finally, he uses Javascript to unmask it when the hamburger menu is clicked. I'm not much of an expert in CSS and I blindly copy pasted the masking bit for the animation.

The tricky part comes next in the javascript. You'll notice he used an on-click event listener onto the hamburger menu by referencing the <em>nav-links</em> using a queryselector which triggers the animation (which simply toggles a css class to the nav-links). But if you know react basics you'd be able to tell that you can't simply copy paste that bit to your react application. But you can do something very similar using <em>refs</em>.

Without getting too deep as to what refs are, they let you reference the elements in the DOM just as a queryselector or the classic '<em>.getElementBy...()</em>' would. If you want to read more about refs, check out this <a href="https://medium.com/@rossbulat/how-to-use-react-refs-4541a7501663#:~:text=React%20Refs%20are%20a%20useful,from%20within%20a%20parent%20component.">medium article</a>. Besides using refs, you'd also need to add an onClick prop to the div that wraps the hamburger menu, and would have to define a method that toggles the css class which executes the animation.
<a id='second_part'></a>
Here's how I did it.

First I had to create the refs in the constructor method of my class component (you can also use refs in functional components).
```react
export default class Header extends React.Component {
  constructor() {
    super()
    this.navLinks = React.createRef();
  }
}
```

Next up, I literally copy pasted the entire <em>nav</em> from Ed's HTML into the render() method, except I had to add classes in jsx rather than actual HTML.

```react
render() {
  return (
    <nav>

      <div ref={this.menu} onClick={this.menuAnimation}>
        <div className="line" />
        <div className="line" />
        <div className="line" />
      </div>

        <ul className="nav-links" ref={this.navLinks}>
            <li onClick={this.menuAnimation}>Home</li>
            <li onClick={this.menuAnimation}>Projects</li>
            <li onClick={this.menuAnimation}>About</li>
        </ul>
      </nav>
    );
  }
```

So I added an onClick event handler to the <em>nav-links</em> div and added the previously created this.navLinks ref to it. You might be wondering why  I added the same event handlers to the nav-links. I'll explain in a bit.
Now we have to define the <em>menuAnimation</em> method. I'll put the entire class in now to avoid confusion.

```react
import React from 'react';

export default class Header extends React.Component {
  constructor() {
    super()
    this.navLinks = React.createRef();
  }

  menuAnimation = () => {
    this.navLinks.current.classList.toggle("open");
  }

  render() {
    return (
      <nav>

        <div className="menu" onClick={this.menuAnimation}>
          <div className="line" />
          <div className="line" />
          <div className="line" />
        </div>

        <ul className="nav-links" ref={this.navLinks}>
          <li onClick={this.menuAnimation}>Home</li>
          <li onClick={this.menuAnimation}>Projects</li>
          <li onClick={this.menuAnimation}>About</li>
        </ul>
      </nav>
    );
  }
}
```

The code that triggers the animation is pretty much the same. The only difference is how the nav-links div is referenced in Vanilla JS and React.
<a id='product'></a>
Here's the end result.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8tcjh1ojk8eyze7w7dwf.gif)

If you followed along by coding you must have realized why I added the menuAnimation method to the nav-linkst too. Because once you toggle the menu and choose one of the nav-links, the menu doesn't close itself (because nothing tells it to!). So you have to add the same toggle method to the nav-links so it closes the hamburger menu before it takes the user to the intended link or page.


----------------------------------------------------------------------


P.S. This was my first ever post on Dev. Would really appreciate some support😊. I'd be grateful if anyone pointed out the mistakes in my writings and hopefully I won't make them next time.
You can tweet me at <a href="https://twitter.com/leadersheir_">@leadersheir_</a> and check out some of my projects on <a href="https://github.com/wari0010">github</a> and <a href="https://codepen.io/waris0010/">codepen</a>.
Stay safe, ya'll...
HAPPY CODING!!!