DEV Community

Cover image for Responsive Navbar in React
Gustavo Scarpim
Gustavo Scarpim

Posted on • Updated on

Responsive Navbar in React

Heeeeeey guys!

My name is Gustavo Scarpim, and I will show you how to make a SIMPLE and RESPONSIVE Navbar.

Creating Navbar

First we will create a file called Burger and import a component called RightNav that we will create right after, inside this file we will put the following code:

import React, { useState } from 'react';
import * as S from './styles';

import RightNav from './RightNav';

const Burger = () => {
  const [open, setOpen] = useState(false)

  return (
    <>
      <S.StyledBurger open={open} onClick={() => setOpen(!open)}>
        <div />
        <div />
        <div />
      </S.StyledBurger>
      <RightNav open={open} />
    </>
  )
}
export default Burger
Enter fullscreen mode Exit fullscreen mode

Then we will create a file called Navbar by importing your logo into a folder of your choice, or you can simply remove it, and we will also import our Burger component that was created just above.

import React from 'react';
import * as S from './styles';

import Logo from '../../assets/logo.png';
import Burger from './Burger';

type Props = {
  children?: any;
}

export default function Navbar(props: Props) {
  return (
    <>
      <S.Nav>
        <S.Logo src={Logo} alt="Etio Soluções" />
      </S.Nav>
      <Burger />
      {props.children}
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

We will create our file called RightNav by importing react-router-dom and calling your images into the assets folder.

import React from 'react'
import * as S from './styles';

import Logo from '../../assets/logo.png';
import IconReact from '../../assets/react.svg';
import IconMegamen from '../../assets/megamen.png';
import IconMario from '../../assets/mario.png';
import IconTurtle from '../../assets/turtle.png';

import { BrowserRouter as Router, Switch, Route, NavLink, Redirect } from "react-router-dom";

type Props = {
  open: boolean;
}

function RightNav(props: Props) {

  return (
    <Router>
      <S.Ul open={props.open}>
        <S.LogoUl src={Logo} alt={'Gustavo Scarpim'} />

        <NavLink to="/menu1"
          activeStyle={{
            fontWeight: "bold",
            color: "#0DADEA"
          }}
        >
          <li>Menu 1</li>
        </NavLink>
        <NavLink to="/menu2"
          activeStyle={{
            fontWeight: "bold",
            color: "#0DADEA"
          }}
        >
          <li>Menu 2</li>
        </NavLink>
        <NavLink to="/menu3"
          activeStyle={{
            fontWeight: "bold",
            color: "#0DADEA"
          }}
        >
          <li>Menu 3</li>
        </NavLink>
        <NavLink to="/menu4"
          activeStyle={{
            fontWeight: "bold",
            color: "#0DADEA"
          }}
        >
          <li>Menu 4</li>
        </NavLink>
      </S.Ul>


      <Switch>
        <Route exact path="/menu1">
          <S.Icon>
            <img src={IconReact} alt="React" />
          </S.Icon>
        </Route>
        <Route exact path="/menu2" >
          <S.Icon>
            <img src={IconMegamen} alt="Megamen" />
          </S.Icon>
        </Route>
        <Route exact path="/menu3" >
          <S.Icon>
            <img src={IconMario} alt="Mario" />
          </S.Icon>
        </Route>
        <Route exact path="/menu4" >
          <S.Icon>
            <img src={IconTurtle} alt="Turtle" />
          </S.Icon>
        </Route>

        <Redirect to='/menu1' />
      </Switch>
    </Router >
  )
}

export default RightNav
Enter fullscreen mode Exit fullscreen mode

Finally, we will create the css with styled-components, just add the following code inside a file called styles.ts

import styled from 'styled-components';

interface INav {
  open: boolean;
  href?: string;
}

export const StyledBurger = styled.div<INav>`
  width: 2rem;
  height: 2rem;
  position: fixed;
  top: 15px;
  right: 20px;
  z-index: 20;
  display: none;

  @media (max-width: 768px) {
    display: flex;
    justify-content: space-around;
    flex-flow: column nowrap;
  }
  div {
    width: 2rem;
    height: 0.25rem;
    background-color: ${(props) => props.open ? '#000' : '#000'};
    border-radius: 10px;
    transform-origin: 1px;
    transition: all 0.3s linear;
    cursor: pointer;
    &:nth-child(1) {
      transform: ${(props) => props.open ? 'rotate(45deg)' : 'rotate(0)'};
    }
    &:nth-child(2) {
      transform: ${(props) => props.open ? 'translateX(100%)' : 'translateX(0)'};
      opacity: ${(props) => props.open ? 0 : 1};
    }
    &:nth-child(3) {
      transform: ${(props) => props.open ? 'rotate(-45deg)' : 'rotate(0)'};
    }
  }
`

export const Nav = styled.nav`
  height: 100%;
  display: flex;
  justify-content: space-between;
  background-color: #fdfdfdfa;
  align-items: center;
  position: relative;

  @media (max-width: 678px) {
    width: 100vw;
  }

  span {
    font-size: 30px;
    @media only screen and (max-width: 600px) {
      font-size: 20px;
      :nth-child(2) {
        font-size: 16px !important;
        margin-top: 0px !important;
      }
    }
  }

`

export const Ul = styled.ul<INav>`
  list-style: none;
  display: flex;
  flex-flow: row nowrap;
  position: absolute;
  width: 90%;
  top: 0;
  justify-content: flex-end;
  margin-top: 0px;
  align-items: center;
  font-size: 18px;
  height: 110px;
  margin-left: 20px;

  a {
    text-decoration: none;
    text-transform: none;
    color: #000;
    cursor: pointer;

    &:hover {
      color: #0DADEA;
    }
  }

  li {
    padding: 18px 10px;
  }

  @media (max-width: 768px) {
    flex-flow: column nowrap;
    background-color: #fdfdfdfa;
    position: fixed;
    transform: ${(props) => props.open ? 'translateX(0)' : 'translateX(100%)'};
    top: -16px;
    right: 0;
    height: 100%;
    width: 180px;
    padding-top: 3.5rem;
    transition: transform 0.3s ease-in-out;
    z-index: 9;
    justify-content: normal;

    li {
      color: #000;
      margin-right: 34px;

      &:hover {
        color: #0DADEA;
      }
    }
  }
`

export const Logo = styled.img`
  margin: 20px 50px 20px 7%;
  width: 160px;
  height: 70px;
  object-fit: contain;

  @media (max-width: 1250px) {
    margin: 20px 50px 20px 5%;
  }

`

export const LogoUl = styled.img`
  margin: 20px 50px 20px 5%;
  display: none;

  @media (max-width: 768px) {
    display: flex;
    width: 160px;
    height: 70px;
    object-fit: contain;
  }
`
export const Icon = styled.div`
  width: 100vw;
  height: calc(100vh - 112px);
  display: flex;
  justify-content: center;
  align-items: center;

  img {
    width: 150px;
    height: 150px;
    pointer-events: none;
    object-fit: contain;

    @media (prefers-reduced-motion: no-preference) {
      animation: App-logo-spin infinite 20s linear;
    }
  }

    @keyframes App-logo-spin {
      from {
        transform: rotate(0deg);
      }
      to {
        transform: rotate(360deg);
      }
  }
`
Enter fullscreen mode Exit fullscreen mode

Finally, we arrive at our main Index our Navbar component to be used in our entire project.

import React from 'react';
import ReactDOM from 'react-dom';
import reportWebVitals from './reportWebVitals';
import Menu from './components/menu/Navbar';

ReactDOM.render(
  <React.StrictMode>

    <Menu />
  </React.StrictMode>,
  document.getElementById('root')
);

reportWebVitals();
Enter fullscreen mode Exit fullscreen mode

And ready, your menu navBar is done
Alt Text

It would look like this one (Changing the images):

Vídeo

See the complete code here on GitHub
Check out the Project in action

Thanks for reading.

Discussion (0)