Los modales (o diálogos) son muy comunes en las interfaces web: inicios de sesión, confirmaciones, mensajes de alerta, etc. Pero también son uno de los componentes más problemáticos en accesibilidad web.
Un modal mal implementado puede dejar atrapado al usuario, impedir el uso del teclado o confundir al lector de pantalla.
En este post veremos cómo hacer modales accesibles, primero con Bootstrap y luego con Tailwind.
Problemas comunes en modales
El foco se pierde → Al abrir un modal, el foco debe moverse al interior.
No hay trampa de foco → El usuario puede tabular y “escapar” del modal sin querer.
Contenido detrás accesible → El contenido de fondo no debería ser navegable mientras el modal esté abierto.
Falta de roles ARIA → Sin
role="dialog"oaria-modal="true", el lector de pantalla no lo entiende como modal.Cierre inaccesible → Botón sin
aria-label, o solo cierre con ratón.
Modal accesible con Bootstrap 5
Bootstrap ya trae un componente modal que resuelve gran parte de la accesibilidad web:
<!-- Botón para abrir modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
Abrir modal
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Título del modal</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
</div>
<div class="modal-body">
Contenido del modal aquí...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
<button type="button" class="btn btn-primary">Guardar cambios</button>
</div>
</div>
</div>
</div>👉 Bootstrap gestiona automáticamente:
El foco se mueve al modal al abrirlo.
El contenido de fondo se bloquea.
aria-modal="true"y roles correctos se aplican.
Modal accesible con Tailwind
Con Tailwind debemos programar la lógica manualmente:
<!-- Botón -->
<button id="openModal" class="px-4 py-2 bg-blue-600 text-white rounded">Abrir modal</button>
<!-- Overlay -->
<div id="modal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"
role="dialog" aria-modal="true" aria-labelledby="modalTitle">
<div class="bg-white rounded-lg shadow-lg w-96 p-6 relative">
<h2 id="modalTitle" class="text-xl font-semibold">Título del modal</h2>
<p class="mt-2">Este es el contenido del modal accesible.</p>
<div class="mt-4 flex justify-end space-x-2">
<button id="closeModal" class="px-4 py-2 bg-gray-300 rounded">Cerrar</button>
<button class="px-4 py-2 bg-blue-600 text-white rounded">Aceptar</button>
</div>
</div>
</div>
<script>
const modal = document.getElementById("modal");
const openBtn = document.getElementById("openModal");
const closeBtn = document.getElementById("closeModal");
openBtn.addEventListener("click", () => {
modal.classList.remove("hidden");
// Mover el foco al modal
modal.querySelector("h2").focus();
});
closeBtn.addEventListener("click", () => {
modal.classList.add("hidden");
openBtn.focus();
});
// Cerrar con Escape
document.addEventListener("keydown", (e) => {
if (!modal.classList.contains("hidden") && e.key === "Escape") {
modal.classList.add("hidden");
openBtn.focus();
}
});
</script>👉 Claves de esta implementación:
role="dialog"+aria-modal="true".Foco automático dentro del modal al abrir.
Retorno del foco al botón al cerrar.
Soporte de teclado (
Escpara cerrar).Fondo inaccesible porque queda fuera de foco.
Buenas prácticas en modales accesibles
Siempre usar
role="dialog"y **aria-modal="true".Mover el foco automáticamente dentro del modal.
Mantener la trampa de foco dentro del modal.
Ofrecer un botón de cierre con
aria-label="Cerrar".Permitir cierre con Esc además del ratón.
Bloquear navegación al contenido de fondo.
Conclusión
Los modales pueden ser uno de los componentes más complicados de hacer accesibles, pero con buenas prácticas y un poco de lógica extra, se puede garantizar que cualquier usuario los use sin problemas.
En Bootstrap la accesibilidad web viene casi lista.
En Tailwind, debemos implementar la gestión de foco y los atributos ARIA manualmente.