Artículo original: How to Build a Dropdown Menu with JavaScript

Si usas internet, es probable que ya hayas te hayas cruzado con un menú desplegable. Los menús desplegables tienen dos usos: recolectar la información ingresada por el usuario en los formularios web e implementar menús de acciones o navegación en aplicaciones web.

Los menús desplegables son una de las mejores maneras de ofrecer distintas opciones dentro de una colección de elementos sin comprometer el flujo de una aplicación. Además de aplicaciones web, también se los utiliza en software, sistemas operativos, etc.

En esta guía, vamos a aprender a hacer un menu desplegable de navegación usando HTML, CSS y JavaScript.

Al final de esta guía, voy a incluir el archivo de codepen para que puedas jugar con él.

dropdown-menu-with-css
Resultado final del menú desplegable

Habiendo cubierto lo fundamental de los menús desplegables, vayamos paso por paso para hacer uno.

Paso 1: Agregar el markup para el menu desplegable.

Dado que vamos a usar iconos en esta guía, lo primero que debemos hacer es importarlos. Para hacerlo más simple, vamos a usar la librería gratuita, Boxicons. Siéntete libre de elegir el ícono que prefieras.

Si bien hay distintas maneras de instalar Boxicons dentro de nuestro sitio, la manera más simple es la de fijar el script dentro de la etiqueta  head de nuestro archivo HTML de este modo:

<head>
   <link 
     href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" 
     rel="stylesheet"
    />
 </head>

Una vez que importamos los íconos, creamos un elemento div con la clase container. Este elemento contendrá otro elemento llamado button y el menú desplegable.

Dentro de este contenedor, creamos el elemento button y le damos la clase y el id btn.  Al botón le vamos a agregar el texto y el ícono de una flecha.

Este es el código para el botón:

<button class="btn" id="btn">
  Dropdown
  <i class="bx bx-chevron-down" id="arrow"></i>
</button>

Luego, vamos a agregar el código del menú desplegable propiamente dicho. Debajo de la etiquetabutton, vamos a crear un elemento div con la clase y el id dropdown. Dentro del elemento div, creamos una etiqueta a para cada elemento del menú, con su texto e ícono respectivo.

Así es cómo debería verse el código:

<div class="dropdown" id="dropdown">
  <a href="#create">
    <i class="bx bx-plus-circle"></i>
    Create New
  </a>
  <a href="#draft">
    <i class="bx bx-book"></i>
    All Drafts
  </a>
  <a href="#move">
    <i class="bx bx-folder"></i>
    Move To
  </a>
  <a href="#profile">
    <i class="bx bx-user"></i>
    Profile Settings
  </a>
  <a href="#notification">
    <i class="bx bx-bell"></i>
    Notification
  </a>
  <a href="#settings">
    <i class="bx bx-cog"></i>
    Settings
  </a>
</div>

Y este es el resultado:

dropdown-menu-markup
Resultado del código del menú desplegable

Todavía no luce bien, así que vamos a darle estilos al menú.

Paso 2: Dándole estilos al menú desplegable

Primero vamos a resetear los márgenes y el padding de cada elemento de la página y guardar alguno de los valores en variables reusables para poder utilizarlos en nuestro archivo CSS. Luego, le daremos al elemento body un estilo global.

@import url(https://fonts.googleapis.com/css?family=Inter:100,200,300,regular,500,600,700,800,900);

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Inter", sans-serif;
  --shadow: rgba(0, 0, 0, 0.05) 0px 6px 10px 0px,
    rgba(0, 0, 0, 0.1) 0px 0px 0px 1px;
  --color: #166e67;
  --gap: 0.5rem;
  --radius: 5px;
}

body {
  margin: 2rem;
  background-color: #b3e6f4;
  font-size: 0.9rem;
  color: black;
}

El próximo paso es darle estilo al botón y al contenedor del menú desplegable. Para agilizar las cosas, solo voy a explicar lo más importante sobre cómo dar estilo.

Copia este código y pégalo en tu archivo CSS:

.btn {
  background-color: white;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  column-gap: var(--gap);
  padding: 0.6rem;
  cursor: pointer;
  border-radius: var(--radius);
  border: none;
  box-shadow: var(--shadow);
  position: relative;
}

.bx {
  font-size: 1.1rem;
}

.dropdown {
  position: absolute;
  width: 250px;
  box-shadow: var(--shadow);
  border-radius: var(--radius);
  margin-top: 0.3rem;
  background: white;
}

.dropdown a {
  display: flex;
  align-items: center;
  column-gap: var(--gap);
  padding: 0.8rem 1rem;
  text-decoration: none;
  color: black;
}

.dropdown a:hover {
  background-color: var(--color);
  color: white;
}

Dado que los menús desplegables suelen ubicarse por sobre los elementos, el botón tiene posición relative y el menú desplegable, absolute. Esto permite que ambos elementos estén cerca uno del otro y que el menú desplegable se ubicará por arriba de otros elementos. De esta manera, al desplegarlo, no afectará el flujo de la página.

Este es el resultado:

dropdown-menu-with-css
Dropdown menu styling 

Ahora que ya le dimos estilo al menú desplegable, queremos que solo aparezca al apretar un botón en vez de hacerlo cuando pasamos con el puntero sobre él.

En un artículo anterior que escribí sobre cómo hacer un modal con JavaScript [en inglés], usé display: none para inicialmente ocultar el elemento modal de la pantalla. Pero lo malo de utilizar esta propiedad es que, de acuerdo con MDN Docs [en inglés], la propiedad no es animable.

Por esto, en esta guía usaremos una manera distinta para ocultar el menú desplegable. Esto lo haremos combinando las propiedades visibility y opacity. Esta es la manera que GitHub utiliza para ocultar sus menús desplegables.

github-dropdown-menu
Menú desplegable en GitHub

Dentro de la clase dropdown que creamos anteriormente, agregamos la propiedad visibility con el valor hidden y la opacidad establecida en 0. Al hacer esto, el menú desplegable aparecerá escondido al cargar la página.

Para mostrar el modal,  vamos a crear una clase separada llamada show. Esta clase va a tener la propiedad visibility con el valor visible y una opacidad de 1. A esta clase la vamos a insertar usando JavaScript.

Este es el código:

.dropdown {
  position: absolute;
  width: 250px;
  box-shadow: var(--shadow);
  border-radius: var(--radius);
  margin-top: 0.3rem;
  background: white;
  transition: all 0.1s cubic-bezier(0.16, 1, 0.5, 1);
    
  transform: translateY(0.5rem);
  visibility: hidden;
  opacity: 0;
}

.show {
  transform: translateY(0rem);
  visibility: visible;
  opacity: 1;
}

.arrow {
  transform: rotate(180deg);
  transition: 0.2s ease;
}

Sumado al código para ocultar el elemento modal, añadimos otra clase para rotar el icono de flecha cuando se aprieta el botón del menú.

Paso 3: Agregando funcionalidad al menú desplegable

Primero, vamos a guardar los distintos elementos en variables para poder reutilizarlos.

const dropdownBtn = document.getElementById("btn");
const dropdownMenu = document.getElementById("dropdown");
const toggleArrow = document.getElementById("arrow");

El próximo paso es crear una función para insertar la clase show del elemento desplegable y rotar la flecha del menú al apretar el botón. A esta función la llamaremos toggleDropdown.

const toggleDropdown = function () {
  dropdownMenu.classList.toggle("show");
  toggleArrow.classList.toggle("arrow");
};

Luego vamos a agregar esta función en el botón del menú desplegable con el método addEventListener para que cada vez que el botón se apriete, active la función que controla que el menú desplegable se oculte o despliegue.

dropdownBtn.addEventListener("click", function (e) {
  e.stopPropagation();
  toggleDropdown();
});

Si no te diste cuenta, añadimos ell método stopPropagation()dentro de la función del menú desplegable. Esto hace que la función del elemento botón no la herede el elemento padre y se ejecute dos veces. Esto lo entenderás más en la próxima sección.

Este es el resultado:

toggle-dropdown-menu-
Despliegue del menú

Cómo cerrar un menú desplegable cuando un elemento del DOM se aprieta

Es posible cerrar un menú desplegable de cuatro formas distintas:

  • Al apretar el botón que lo activa
  • Al hacer clic sobre cualquiera de sus elementos individuales
  • Al hacer clic fuera del menú (en el body de la página)
  • Al apretar el botón Escape o el botón de flecha hacia abajo del teclado.

Pero en esta guía nos vamos a concentrar en los primeros tres.

Primero, vamos a seleccionar el elemento raíz <html> con document.documentElement. Y como hicimos anteriormente, vamos a insertar la función toggleDropdown() dentro de él.

Pero esta vez queremos poner una condición que chequee si el menú desplegable contiene o no la clase show. Solo cuando la tenga vamos a querer que se active la función para ocultar el menú.

document.documentElement.addEventListener("click", function () {
  if (dropdownMenu.classList.contains("show")) {
    toggleDropdown();
  }
});

Este es el resultado final:

close-dropdown-when-dom-element-is-clicked
Menú desplegable cerrado cuando se hace clic sobre un elemento del DOM

Y así es como se hace un menú desplegable con JavaScript. Abajo está el archivo de codepen para ver el menú desplegable en acción.

Conclusión

Espero, de corazón, que este post te haya resultado útil o interesante. Si fue así, te pido que lo compartas con tus amigos o suscríbete a mi blog así no te pierdes ningún post. Gracias por leer.

GitHub | Twitter | Blog | Portfolio