ProgramingWeb

¿Cómo crear un menú hamburguesa navbar responsive con reactjs?

Empecemos por lo primero, agregamos a nuestro archivo app.js el componente Header que será el contenedor del menú.

import React from "react"
import Header from "./Header"

export default function App() {
  return (
    <>
      <Header />
    </>
  )
}

Creando el componente Header.js para hacer un navbar o cabecera responsive.

Toda la lógica de nuestro menú responsive va a vivir dentro del componenter Header.js, aqí controlaremos el estado del navbar.

import React, { useState } from "react"
import { HeaderWrapper } from "./styles/Header"
import Navbar from "./Navbar"
import MenuButton from "./MenuButton"

function Header() {
  const [open, setOpen] = useState(false)

  const handleClick = () => {
    setOpen(!open)
  }

  return (
    <HeaderWrapper>
      <h2>Logo</h2>
      <Navbar open={open} />
      <MenuButton open={open} handleClick={handleClick} />
    </HeaderWrapper>
  )
}

export default Header

Explicación del estado de este componente: necesitamos saber cuando el menú va a estar abierto en su versión mobile, por eso necesitamos una variable open, támbien debemos crear una función que escuchara un evento de click que cambiara el valor de la variable open. Ahora desglosamos el código paso a paso.

  • Lo primero que debemos hacer es importar el gancho useState. directamente desde react.

  • Luego importamos los componentes HeaderWrapper, Navbar, y MenuButton. Todos son echos con styled-components.

  • Dentro de nuestro componente Header creamos un estado sencillo usando el hook useState(). Este estado será el encargado de controlar si el menú se muestra o desaparece.

const [open, setOpen] = useState(false)
  • Creamos la función handleClick que cambia el estado de la variable open al valor opuesto, es decir si es true lo cambia a false y viceversa setOpen(!open) esta función se ejecutará cada vez que hagamos click en el componente MenuButton. Determinándo si el menú esta abierto o cerrado.

  • Como prop le pasamos la variable open al componente Navbar y MenuButton

  • Al componente MenuButton también le pasamos la función handleClick para que se encargue de cambiar el estado.

const handleClick = () => {
  setOpen(!open)
}

Creamos el componente HeaderWrapper en un archivo HeaderStyles.js

Agregamos algunos estilos que harán que la cabecera se vea un poco mejor.

import styled from "styled-components"

export const HeaderWrapper = styled.header`
  height: 10vh;
  display: flex;
  justify-content: space-between;
  align-items: center;
`
  • Importamos styled de styled-components para poder crear nuestro elemento

  • Es una cabecera muy sencilla, le asignamos una altura y separamos sus elementos usando flexbox. Este no es un tutorial enfocado en el diseño, puedes mejorar el estilo a tu gusto.

Creando El componente Navbar.js para nuestro menú responsive con react

Este componente sera el contenedor de los enlaces de navegación de nuestro sitio por lo tanto es muy importante su estructura.

import React from "react"
import { NavbarWrapper } from "./styles/NavbarStyles"

function Navbar({ open }) {
  return (
    <NavbarWrapper open={open}>
      <a href="#">Link</a>
      <a href="#">Link</a>
      <a href="#">Link</a>
      <a href="#">Link</a>
    </NavbarWrapper>
  )
}

export default Navbar
  • Importamos el contenedor NavBarWrapper que haremos con styled-components.

  • Creamos el componente Navbar recibimos la propiedad open function Navbar({ open })

  • Al elemento NavWrapper le pasamos la propiedad open que luego usaremos para mostrar el menú evaluando si es true o false

  • Por último agregamos varios enlaces ancla.

Aquí se empieza a poner lindo. Creamos nuestro archvio NavbarStyles.js

Creando el NavbarWrapper con styled-components

import styled from "styled-components"

export const NavbarWrapper = styled.nav`
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
  background: turquoise;
  position: fixed;
  top: 10vh;
  right: ${props => (props.open ? "0" : "-100%")};
  width: 100%;
  height: 90vh;
  transition: right 0.3s linear;

  @media only screen and (min-width: 624px) {
    flex-direction: row;
    position: initial;
    height: auto;
    justify-content: center;
    background: white;
  }

  a {
    padding: 0.5rem 0.8rem;
    color: grey;
    text-decoration: none;
  }
`
  • Agregamos algunas propiedades de flexbox para poner el menú en forma vertical (la versión que se mostrará en mobiles).
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
  • Establecemos el valor de la propiedad position en fixed para que el Nabvar siempre este fijo.

  • La propiedad top la establecemos en 10vh, por que es la misma altura del header, esto pone nuestro menú justo por debajo de la cabecera.

  • El valor de la propiedad right estará condicionada por el prop open que pasamos al componente NavbarWrapper right: \${props => (props.open ? "0" : "-100%")}; si es true el valor es 0 lo que hace que el menú se muestre, y si es false el valor es -100% esto esconderá el menú.

  • Asignamos un ancho del 100%, y una altura de 90vh para que ocupe el resto de la pantalla. También agregamos una transición que animará la propiedad right para que el menú entre a la pantalla suavemente.

  • Por último agregamos dentro de una media query algunas propiedades para que el navbar en pantallas más grandes se muestre horizontalmente y dentro del header.

Creando el componente MenuButton.js

Este componente será el encargado de abrir y cerrar el menú.

import React from "react"
import styled from "styled-components"

const MenuButtonWrapper = styled.button`
  border: none;
  box-shadow: 0px 0px 1px rgb(50, 50, 50);
  margin-top: 1.3rem;

  @media only screen and (min-width: 624px) {
    display: none;
  }
`

function MenuButton({ open, handleClick }) {
  return !open ? (
    <MenuButtonWrapper onClick={handleClick}>
      <svg viewBox="0 0 100 80" width="30" height="30" fill="#2962ff">
        <rect width="90" height="10" />
        <rect y="30" width="80" height="10" />
        <rect y="60" width="70" height="10" />
      </svg>
    </MenuButtonWrapper>
  ) : (
    <MenuButtonWrapper onClick={handleClick}>
      <svg
        className="svg-icon"
        width="30"
        height="30"
        viewBox="0 0 20 20"
        fill="#2962ff"
      >
        <path d="M15.898,4.045c-0.271-0.272-0.713-0.272-0.986,0l-4.71,4.711L5.493,4.045c-0.272-0.272-0.714-0.272-0.986,0s-0.272,0.714,0,0.986l4.709,4.711l-4.71,4.711c-0.272,0.271-0.272,0.713,0,0.986c0.136,0.136,0.314,0.203,0.492,0.203c0.179,0,0.357-0.067,0.493-0.203l4.711-4.711l4.71,4.711c0.137,0.136,0.314,0.203,0.494,0.203c0.178,0,0.355-0.067,0.492-0.203c0.273-0.273,0.273-0.715,0-0.986l-4.711-4.711l4.711-4.711C16.172,4.759,16.172,4.317,15.898,4.045z" />
      </svg>
    </MenuButtonWrapper>
  )
}

export default MenuButton
  • Creamos el componente MenuButtonWrapper con styled-components, Le asignamos algunos estilos base y una media query que hará que el botón desaparezca cuando la pantalla tenga un ancho mayor a 624px.

  • Creamos El componente MenuButton que recibe las props function MenuButton({ open, handleClick }).

  • Dentro del componente hacemos una condicional usando el operador ternario.

  • Si open es false muestra el típico icono de menú hamburguesa. Y si es true mostrará un icono de cerrar.

  • Por último a los dos botones les pasamos la función handleClick dentro del evento onClick, para que cada vez que se haga click sobre ellos cambie el valor de la variable open.

Ya terminamos tienes un menú hamburguesa totalmente funcional, si los vas a usar para un proyecto puedes adaptarlo con tu propio estilo y hacer que se vea mucho mejor, para finalizar quiero agradecerte por leernos y puedes encontrar todo el código de este tutorial en el siguiente: CodeSanbox