Components
Dialog
Dialog and Modal are the same underlying <dialog class="tf-modal"> element. Modal documents the composed application patterns (headers, footers, sizes, scrollable bodies). This page documents the native element contract itself — including the one thing Modal's own patterns don't cover: a non-modal dialog that doesn't block the rest of the page.
How It Works
Every dialog is opened through TicFrame.Modal.show() (or a data-tf-toggle="modal" trigger), which picks between the browser's two native open methods based on one attribute.
Modal vs. non-modal
By default a dialog opens with the native showModal(): it gets a ::backdrop, blocks interaction with the rest of the page, and traps focus. Add data-tf-dialog-modal="false" and TicFrame uses show() instead — no backdrop, no focus trap, the page behind stays fully usable.
Alert dialogs
Add role="alertdialog" for a dialog that interrupts to demand a decision (typically a destructive confirmation) — screen readers announce it more assertively than a plain dialog.
Scroll lock scope
Background scroll only locks while a modal dialog is open. A non-modal dialog never locks scroll, even if a modal one is opened afterward and then closed while the non-modal one is still up.
Escape behavior
The browser only wires Escape-to-close for dialogs opened with showModal(). A non-modal dialog needs an explicit data-tf-dismiss="modal" control — Escape does nothing to it, which is native, not a TicFrame gap.
Live Examples
Modal dialog (default)
Blocks the rest of the page. This is the same behavior Modal's patterns all build on.
<button type="button" class="tf-btn tf-btn-primary" data-tf-toggle="modal" data-tf-target="#dialog-modal-demo">Open modal dialog</button>
<dialog id="dialog-modal-demo" class="tf-modal tf-modal-sm tf-modal-center" aria-labelledby="dialog-modal-demo-title">
<div class="tf-modal-body">
<h3 id="dialog-modal-demo-title">Modal dialog</h3>
<p>Background scroll is locked...</p>
<button type="button" data-tf-dismiss="modal">Close</button>
</div>
</dialog>Non-modal dialog
data-tf-dialog-modal="false" on the dialog itself. No backdrop, no scroll lock — try scrolling or clicking elsewhere on the page while this is open.
<button type="button" class="tf-btn" data-tf-toggle="modal" data-tf-target="#dialog-nonmodal-demo">Open non-modal dialog</button>
<dialog id="dialog-nonmodal-demo" class="tf-modal tf-modal-sm" data-tf-dialog-modal="false" aria-labelledby="dialog-nonmodal-demo-title">
<div class="tf-modal-body">
<h3 id="dialog-nonmodal-demo-title">Non-modal dialog</h3>
<p>The page behind this stays interactive...</p>
<button type="button" data-tf-dismiss="modal">Dismiss</button>
</div>
</dialog>Alert dialog
role="alertdialog" for a destructive confirmation — the safe action is first and focused by default.
<dialog class="tf-modal tf-modal-sm tf-modal-center" role="alertdialog"
aria-labelledby="dialog-alert-demo-title" aria-describedby="dialog-alert-demo-desc">
<div class="tf-modal-body">
<h3 id="dialog-alert-demo-title">Delete this project?</h3>
<p id="dialog-alert-demo-desc">This can't be undone.</p>
<button type="button" autofocus data-tf-dismiss="modal">Cancel</button>
<button type="button" class="tf-btn-danger" data-tf-dismiss="modal">Delete</button>
</div>
</dialog>Accessibility
| Requirement | TicFrame guidance |
|---|---|
| Name | aria-labelledby pointing at the visible title, for both modal and non-modal dialogs. |
| Alert dialogs | Use role="alertdialog" plus aria-describedby for destructive confirmations; keep it modal so the decision can't be skipped. |
| Non-modal focus | TicFrame still moves focus into a non-modal dialog on open and restores it on close — only the trap and backdrop are skipped, not focus management. |
| Escape | Only closes modal dialogs (native browser behavior). Give a non-modal dialog a visible dismiss control since users can't rely on Escape. |
API Reference
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-tf-dialog-modal | "false" (only meaningful value) | unset (modal) | Opens with native show() instead of showModal(): no backdrop, no focus trap, no scroll lock. |
Triggers, dismiss buttons, methods, and events are shared with Modal — see the Modal API reference. TicFrame.Modal.show() reads data-tf-dialog-modal off the dialog element itself, so the same method opens both kinds.
Troubleshooting
| Symptom | Fix |
|---|---|
| Escape doesn't close my non-modal dialog | Expected — only showModal()-opened dialogs get native Escape handling. Add a visible dismiss button. |
| Non-modal dialog still blocks the page | Confirm data-tf-dialog-modal="false" is on the <dialog> element itself, not the trigger button. |
| Background scroll stays locked after closing a non-modal dialog | This shouldn't happen — non-modal dialogs never lock scroll in the first place. Check whether a separate modal dialog is also open. |
| Alert dialog closes on backdrop click when it shouldn't | Add data-tf-modal-backdrop="static" to require an explicit button choice. |