Ir al contenido

Dropdown

.dropdown muestra un menú bajo un botón, con enlaces o acciones simples. Necesita ds-uikit.js.

  • Dentro de .dropdown van el botón, con data-ds-toggle="dropdown" y aria-expanded="false", y el menú dropdown__menu con hidden.
  • El menú lleva enlaces (<a href>) o botones (<button type="button">) con la clase dropdown__item. También acepta dropdown__header y dropdown__divider.
  • dropdown__toggle en el botón agrega una flecha que gira al abrir (opcional).
<div class="dropdown">
<button type="button" class="btn dropdown__toggle" data-ds-toggle="dropdown" aria-expanded="false">Productos</button>
<div class="dropdown__menu" hidden>
<a class="dropdown__item" href="#">dsRest</a>
<a class="dropdown__item" href="#">dsStore</a>
<a class="dropdown__item" href="#">dsStepflow</a>
</div>
</div>

Para acciones en la misma página (duplicar, eliminar), usa <button type="button">. Al elegir un ítem, el menú se cierra y el foco vuelve al botón.

<div class="dropdown">
<button type="button" class="btn dropdown__toggle" data-ds-toggle="dropdown" aria-expanded="false">Acciones</button>
<div class="dropdown__menu" hidden>
<button type="button" class="dropdown__item">Duplicar</button>
<button type="button" class="dropdown__item">Mover a otra carpeta</button>
<button type="button" class="dropdown__item">Eliminar</button>
</div>
</div>

Por defecto el menú se alinea con el borde izquierdo del botón. dropdown__menu--end lo alinea con el derecho: úsalo en botones pegados al borde derecho, como el menú de usuario del header.

<div class="dropdown">
<button type="button" class="btn dropdown__toggle" data-ds-toggle="dropdown" aria-expanded="false">Mi cuenta</button>
<div class="dropdown__menu dropdown__menu--end" hidden>
<a class="dropdown__item" href="#">Perfil</a>
<a class="dropdown__item" href="#">Pedidos</a>
<a class="dropdown__item" href="#">Cerrar sesión</a>
</div>
</div>

Si el menú no cabe a lo ancho, se corre para no salirse de la pantalla.

dropdown--up abre el menú sobre el botón, por ejemplo en un pie de página.

<div class="dropdown dropdown--up">
<button type="button" class="btn dropdown__toggle" data-ds-toggle="dropdown" aria-expanded="false">Compartir</button>
<div class="dropdown__menu" hidden>
<a class="dropdown__item" href="#">Facebook</a>
<a class="dropdown__item" href="#">LinkedIn</a>
<button type="button" class="dropdown__item">Copiar enlace</button>
</div>
</div>

Si no cabe hacia donde se abre y al otro lado hay más espacio, el menú se da vuelta solo (el JS agrega is-flipped a .dropdown).

dropdown__header titula un grupo de ítems y <hr class="dropdown__divider"> los separa.

<div class="dropdown">
<button type="button" class="btn dropdown__toggle" data-ds-toggle="dropdown" aria-expanded="false">Mi cuenta</button>
<div class="dropdown__menu" hidden>
<div class="dropdown__header">Cuenta</div>
<a class="dropdown__item" href="#">Perfil</a>
<a class="dropdown__item" href="#">Configuración</a>
<hr class="dropdown__divider">
<div class="dropdown__header">Ayuda</div>
<a class="dropdown__item" href="#">Centro de ayuda</a>
<a class="dropdown__item" href="#">Contacto</a>
<hr class="dropdown__divider">
<button type="button" class="dropdown__item">Cerrar sesión</button>
</div>
</div>
  • Actual: aria-current="page" en el enlace a la página en que estás (o is-active, solo visual).
  • Deshabilitado: un enlace sin href y con aria-disabled="true", o un botón con disabled. No se puede elegir y las flechas lo saltan.
<div class="dropdown">
<button type="button" class="btn dropdown__toggle" data-ds-toggle="dropdown" aria-expanded="false">Categorías</button>
<div class="dropdown__menu" hidden>
<a class="dropdown__item" href="#" aria-current="page">Todas</a>
<a class="dropdown__item" href="#">Diseño</a>
<a class="dropdown__item" href="#">Desarrollo</a>
<a class="dropdown__item" aria-disabled="true">Eventos</a>
</div>
</div>
<div class="dropdown">
<button type="button" class="btn dropdown__toggle" data-ds-toggle="dropdown" aria-expanded="false">Archivo</button>
<div class="dropdown__menu" hidden>
<button type="button" class="dropdown__item">Guardar</button>
<button type="button" class="dropdown__item" disabled>Deshacer</button>
<button type="button" class="dropdown__item">Exportar</button>
</div>
</div>

El menú no se corta con el scroll del cuerpo del modal: dentro de un contenedor con overflow, el JS lo ubica con position: fixed. Escape cierra primero el dropdown y después el modal.

<button type="button" class="btn btn--primary" data-ds-toggle="modal" data-ds-target="#modal-compartir">Compartir archivo</button>
<div class="modal" id="modal-compartir" role="dialog" aria-modal="true" aria-labelledby="modal-compartir-titulo" hidden>
<div class="modal__backdrop"></div>
<div class="modal__dialog">
<div class="modal__header">
<h2 class="modal__title" id="modal-compartir-titulo">Compartir archivo</h2>
<button type="button" class="modal__close" data-ds-dismiss="modal" aria-label="Cerrar"></button>
</div>
<div class="modal__body">
<p>Elige quién puede ver el archivo.</p>
<div class="dropdown">
<button type="button" class="btn dropdown__toggle" data-ds-toggle="dropdown" aria-expanded="false">Permisos</button>
<div class="dropdown__menu" hidden>
<button type="button" class="dropdown__item">Solo yo</button>
<button type="button" class="dropdown__item">Mi equipo</button>
<button type="button" class="dropdown__item">Cualquiera con el enlace</button>
</div>
</div>
</div>
<div class="modal__footer">
<button type="button" class="btn" data-ds-dismiss="modal">Cancelar</button>
<button type="button" class="btn btn--primary" data-ds-dismiss="modal">Listo</button>
</div>
</div>
</div>
  • Se abre con un clic en el botón (data-ds-toggle="dropdown" abre el .dropdown que lo contiene) o con la flecha abajo, que además enfoca el primer ítem (la flecha arriba enfoca el último).
  • Se cierra con un clic fuera, con Escape, al elegir un ítem y al salir con Tab. Con Escape o al elegir un ítem, el foco vuelve al botón.
  • Solo hay un dropdown abierto a la vez: al abrir uno, se cierra el anterior.
  • Actualiza aria-expanded en el botón. Aparece y desaparece con un fundido y un leve desplazamiento. Queda oculto con hidden, sin quitarlo del DOM.
Atributo Qué hace
data-ds-toggle="dropdown" En el botón: abre o cierra el .dropdown que lo contiene. Con data-ds-target, el indicado.
data-ds-dismiss="dropdown" Cierra el dropdown que contiene al elemento (por ejemplo, un botón dentro de un formulario en el menú).
const cuenta = dsUIKit.dropdown('#menu-cuenta'); // .dropdown o selector
cuenta.open();
cuenta.close();
cuenta.toggle();
cuenta.isOpen; // true o false
// Saber qué ítem se eligió
document.querySelector('#menu-cuenta').addEventListener('ds:close', (e) => {
if (e.detail.trigger?.matches('.dropdown__item')) console.log(e.detail.trigger.textContent);
});

En React, los atributos funcionan igual. Para abrirlo desde código: dropdown(ref.current).open() (con import { dropdown } from './js/ds-uikit.esm.js').

Evento Cuándo
ds:open Antes de abrirse. Con preventDefault() se cancela.
ds:opened Al terminar de abrirse.
ds:close Antes de cerrarse. Cancelable.
ds:closed Al terminar de cerrarse.

event.detail.trigger es el botón que lo abrió o cerró, el ítem elegido, o null si fue con un clic fuera, Escape, Tab o la API. Más detalles en JavaScript.

  • Sigue el patrón disclosure (botón que muestra u oculta contenido), sin role="menu": sirve para enlaces y acciones simples. Los lectores de pantalla anuncian el botón como contraído o expandido gracias a aria-expanded.
  • Teclado: Enter o Espacio abren y cierran; la flecha abajo abre y enfoca el primer ítem; dentro del menú, las flechas, Inicio y Fin recorren los ítems (saltan los deshabilitados); Tab avanza al siguiente elemento y cierra al salir; Escape cierra y devuelve el foco al botón.
  • Si el botón solo tiene un ícono, ponle aria-label (por ejemplo, aria-label="Menú de usuario").
  • El ítem de la página actual lleva aria-current="page". is-active solo cambia el aspecto.
  • dropdown__header es texto, no un título: no altera la estructura de encabezados de la página.
  • Con «reducir movimiento» activado, abre y cierra sin transición.
Clase Uso
dropdown Contenedor del botón y el menú.
dropdown--up El menú se abre hacia arriba.
dropdown__toggle En el botón (opcional): flecha que gira al abrir.
dropdown__menu Menú. Lleva hidden mientras está cerrado.
dropdown__menu--end Alinea el menú con el borde derecho del botón.
dropdown__item Ítem: <a href> o <button type="button">.
dropdown__header Título de un grupo de ítems.
dropdown__divider Separador (<hr>).
is-active Ítem actual (solo visual; mejor aria-current).
is-disabled Ítem deshabilitado (solo visual; mejor aria-disabled="true" o disabled).
VariableValor por defectoUso
--ds-dropdown-min-width10remAncho mínimo del menú (si el botón es más ancho, toma su ancho).
--ds-dropdown-gapvar(--ds-space-1)Separación entre el botón y el menú.
--ds-dropdown-padding-yvar(--ds-space-2)Espacio vertical interno del menú.
--ds-dropdown-bgvar(--ds-color-surface)Fondo del menú.
--ds-dropdown-colorvar(--ds-color-text)Color del texto.
--ds-dropdown-border-colorvar(--ds-color-border)Color del borde del menú.
--ds-dropdown-radiusvar(--ds-radius-md)
--ds-dropdown-shadowvar(--ds-shadow-md)
--ds-dropdown-font-sizevar(--ds-font-size-sm)
--ds-dropdown-item-padding-yvar(--ds-space-2)Espacio vertical interno del ítem.
--ds-dropdown-item-padding-xvar(--ds-space-4)Espacio horizontal interno de ítems y encabezados.
--ds-dropdown-item-gapvar(--ds-space-2)Separación entre ícono y texto.
--ds-dropdown-item-hover-colorvar(--ds-dropdown-color)Color del ítem en hover y con foco.
--ds-dropdown-item-hover-bgcolor-mix(in srgb, var(--ds-color-text) 6%, var(--ds-color-surface))Fondo del ítem en hover y con foco.
--ds-dropdown-item-active-colorvar(--ds-color-primary-hover)Color del ítem actual.
--ds-dropdown-item-active-bgcolor-mix(in srgb, var(--ds-color-primary) 12%, var(--ds-color-surface))Fondo del ítem actual.
--ds-dropdown-item-active-font-weightvar(--ds-font-weight-semibold)Peso del ítem actual.
--ds-dropdown-item-disabled-opacity0.5Opacidad de un ítem deshabilitado.
--ds-dropdown-icon-size1.25emTamaño de los íconos de los ítems.
--ds-dropdown-header-colorvar(--ds-color-text-muted)Color del encabezado (dropdown__header).
--ds-dropdown-header-font-sizevar(--ds-font-size-xs)Tamaño del encabezado.
--ds-dropdown-divider-colorvar(--ds-color-border)Color del separador (dropdown__divider).
--ds-dropdown-focus-colorvar(--ds-color-primary)Color del contorno de foco.
--ds-dropdown-offset0.5remDesplazamiento del menú hacia el botón al abrir y cerrar.
--ds-dropdown-transition-durationvar(--ds-duration-fast)Duración del fundido al abrir y cerrar.
--ds-dropdown-z-indexvar(--ds-z-dropdown)Capa del menú (z-index).