Diálogo (dialog)
Un modal construido sobre el elemento nativo <dialog>. El navegador aporta la capa superior, el fondo inerte y Escape; iVOLT añade la colocación del foco, su devolución, el cierre al pulsar el fondo, los disparadores declarativos y los eventos cancelables.
<a class="iv-button iv-button--primary" href="#signup" data-iv-open="signup">Create account</a>
<dialog class="iv-dialog" id="signup" data-iv-component="dialog" data-iv-initial-focus="#signup-email" aria-labelledby="signup-title">
<form method="dialog" class="iv-dialog__panel">
<header class="iv-dialog__header">
<h2 class="iv-dialog__title" id="signup-title">Create account</h2>
<button class="iv-button iv-button--ghost iv-button--icon" type="button" data-iv-close aria-label="Close">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg>
</button>
</header>
<div class="iv-dialog__body iv-stack">
<p class="iv-u-m-0">Demo dialog. Nothing is sent anywhere.</p>
<div class="iv-field">
<label class="iv-label" for="signup-email">Work email</label>
<input class="iv-input" id="signup-email" type="email" autocomplete="email">
</div>
</div>
<footer class="iv-dialog__footer">
<a class="iv-button iv-button--ghost" href="#" data-iv-close>Cancel</a>
<button class="iv-button iv-button--primary" value="confirm">Continue</button>
</footer>
</form>
</dialog>// data-iv-component="dialog"
{
open: "signup",
initialFocus: "#signup-email",
close: true,
}Marcado
Dale al diálogo data-iv-component="dialog", un id y un nombre accesible (aria-labelledby). Los disparadores usan data-iv-open="id"; cualquier elemento interior con data-iv-close lo cierra. Un <form method="dialog"> hace que los botones cierren el diálogo con su value como valor de retorno.
JavaScript
import { Dialog } from "@intervolutions/ivolt/dialog";
const dialog = Dialog.getOrCreate(document.getElementById("signup"), { closeOnBackdrop: false });
dialog.open({ trigger: button });
dialog.element.addEventListener("iv:close", (e) => { if (e.detail.reason === "escape" && dirty) e.preventDefault(); });Opciones (defaults < data-iv-* < JS)
| Opción | Atributo | Por defecto | Efecto |
|---|---|---|---|
closeOnBackdrop | data-iv-close-on-backdrop | true | Pulsar fuera del panel cierra. |
closeOnEscape | data-iv-close-on-escape | true | Escape cierra (el cancel nativo se intercepta siempre para que el evento siga siendo cancelable). |
initialFocus | data-iv-initial-focus | null | Selector que recibe el foco al abrir; si no, el primer elemento enfocable y, en su defecto, el propio diálogo. |
returnFocus | data-iv-return-focus | true | El foco vuelve al disparador al cerrar. |
Métodos y eventos
open({ trigger }), close(reason, returnValue), toggle(), destroy(), isOpen, returnValue. Los eventos se propagan desde el elemento del diálogo: iv:open e iv:close son cancelables; después llegan iv:opened e iv:closed. detail.reason es uno de trigger, escape, backdrop, form, api o external.
Teclado
Tab y Mayús+Tab se quedan dentro del modal (comportamiento del navegador con showModal); Escape cierra; Enter en el formulario envía y cierra. El foco vuelve al disparador.
Sin JavaScript
El disparador es un enlace al id del diálogo. Con JavaScript el enlace se intercepta y la URL no cambia. Sin él, .iv-dialog:target muestra el diálogo como un bloque estático con su enlace de cierre. Mantén el contenido esencial accesible también desde otro sitio; un diálogo no es una página.
Errores frecuentes
- Llamar a
dialog.close()directamente sobre el elemento: funciona, peroiv:closeno puede cancelarlo y el motivo pasa a serexternal. - Un disparador dentro del diálogo que apunta a sí mismo.
- Sin nombre accesible (
aria-labelledbyoaria-label).