Recipe
Modal
A modal capsule controlled by data API triggers.
Markup
<button data-ui-toggle="modal" data-ui-action="open" data-target="#confirm">
Delete account
</button>
<dialog ui-modal id="confirm">
<h2>Are you sure?</h2>
<p>This cannot be undone.</p>
<button ref="cancel">Cancel</button>
<button ref="confirm">Delete</button>
</dialog>Capsule
import { UI, Capsule } from "tiny-engine-core";
class Modal extends Capsule {
constructor(el, options) {
super(el, options);
this.lastFocus = null;
this.on(this.refs.cancel, "click", () => this.close());
this.on(this.refs.confirm, "click", () => {
const event = this.emit("modal:confirm", null, { cancelable: true });
if (!event.defaultPrevented) this.close();
});
this.on(document, "keydown", (event) => {
if (event.key === "Escape" && this.el.open) this.close();
});
}
open() {
this.lastFocus = document.activeElement;
this.el.showModal();
this.refs.confirm.focus();
}
close() {
this.el.close();
this.lastFocus?.focus();
}
}
UI.register("modal", Modal);
UI.init();
UI.observe();The dialog host mounts from ui-modal. The trigger calls the public open() method through data-ui-toggle, data-ui-action, and data-target. Confirmation emits a cancellable modal:confirm event.