Modal

Ventana modal para mostrar contenido o acciones sobre una capa superpuesta.

Estado: draft

Vista Previa

# Modal

El componente modal proporciona una ventana superpuesta que bloquea la interacción con el resto de la página, centrando la atención del usuario en una tarea, información o decisión importante.

Cuándo usar

- Para solicitar confirmación sobre acciones destructivas o importantes. - Para mostrar formularios o tareas breves sin perder el contexto de la página actual. - Para presentar información crítica que requiere atención inmediata.

Cuándo NO usar

- Para mensajes de éxito o notificaciones no bloqueantes (utiliza *Toast* o *Alert*). - Si el contenido es muy extenso y requiere navegación o múltiples pasos complejos (es preferible una página dedicada). - No anides modales (abrir una modal sobre otra modal).

Estructura

El componente base consta de:

Variantes

- Default: Tamaño por defecto (máximo 560px de ancho adaptado del sistema de columnas). - Large: Utiliza el modificador .modal--large en el contenedor principal para un tamaño más amplio (máximo 850px), útil para contenidos más extensos.

Accesibilidad (HTML/CSS)

- El contenedor .modal__dialog debe tener el rol role="dialog" y el atributo aria-modal="true". - Utiliza aria-labelledby en el .modal__dialog apuntando al id del .modal__title para proporcionar un nombre accesible. - Si hay un texto descriptivo adicional clave, se puede enlazar con aria-describedby (apuntando al ID del .modal__body). - El botón de cierre utiliza un <button> nativo con su correspondiente aria-label="Cerrar modal". - Los estilos de foco visible están definidos mediante :focus-visible.

Comportamiento Interactivo (Requiere JavaScript)

La implementación proporcionada cubre la estructura semántica y el diseño visual mediante HTML y CSS. Para que la modal sea completamente funcional y accesible de manera interactiva, se requiere implementar el siguiente comportamiento con JavaScript:
  1. Apertura y Cierre:

- Alternar la clase .modal--open en el contenedor .modal y actualizar aria-hidden según el estado. - Restablecer el foco al botón o elemento que disparó la modal una vez que esta se cierra.

  1. Focus Trap (Trampa de foco):

- Al abrir la modal, el foco debe moverse al primer elemento interactivo dentro del diálogo (o al propio .modal__dialog si no hay interactivos). - El foco debe quedar atrapado dentro del .modal__dialog. Al presionar Tab o Shift + Tab, la navegación debe ciclar únicamente por los elementos de la modal, sin salir al fondo de la página.

  1. Cierre por Teclado y Clic:

- Detectar la tecla Escape (Esc) para cerrar la modal inmediatamente. - Detectar el evento de clic en el contenedor exterior (.modal) para cerrar la modal cuando el usuario hace clic en el fondo oscurecido (backdrop), si procede.

  1. Bloqueo de Scroll (Body):

- Aplicar overflow: hidden al elemento <body> o <html> cuando la modal esté abierta para evitar que el usuario pueda hacer scroll en la página subyacente.

HTML

<div class="modal modal--open" style="position: relative; z-index: 1;">
  <div class="modal__dialog" role="dialog" aria-modal="true" aria-labelledby="modal-title">
    <div class="modal__header">
      <h2 class="modal__title" id="modal-title">Modal heading</h2>
      <button type="button" class="modal__close" aria-label="Cerrar modal">
        <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
          <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" />
        </svg>
      </button>
    </div>
    <div class="modal__body">
      <p>Horem ipsum dolor sit amet, consectetur adipiscing elit. Nunc vulputate libero et velit interdum, ac aliquet odio mattis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.</p>
    </div>
    <div class="modal__footer">
      <button type="button" class="gn-button gn-button--primary gn-button--md">
        <span class="gn-button__label">Acción</span>
      </button>
      <button type="button" class="gn-button gn-button--secondary gn-button--md">
        <span class="gn-button__label">Acción</span>
      </button>
    </div>
  </div>
</div>