Modal
A centered overlay dialog, fully controlled by the parent via open. Used for
confirmation flows (e.g. Settings' "Reset all settings?").
Selector: tip-modal
API
| Name | Type | Default | Description |
|---|---|---|---|
open (input) |
boolean |
false |
Whether the modal renders. The component never sets this itself — the parent must flip it to false in its close handler. |
heading (input) |
string |
'' |
Dialog heading, also wired to aria-labelledby. |
close (output) |
void |
— | Emitted on backdrop click, Escape, or the header × button. |
| default slot | content | — | Dialog body. |
[primary-action] (slot) |
content | — | Primary footer button (rendered last / right-most). |
[secondary-action] (slot) |
content | — | Secondary footer button (rendered first). |
Usage
<tip-modal [open]="resetModalOpen()" heading="Reset all settings?" (close)="closeResetModal()">
<p>This restores every General setting to its default value.</p>
<tip-button secondary-action variant="secondary" (clicked)="closeResetModal()">Cancel</tip-button>
<tip-button primary-action variant="critical" (clicked)="confirmReset()">Reset</tip-button>
</tip-modal>
Notes
- Gotcha:
closeonly signals intent — it does not close the modal itself. The parent'sopensignal must be updated in the(close)handler (seeSettingsGeneral.closeResetModal()), otherwise the modal stays open after a backdrop click or Escape. - Backdrop click only closes when the click target is the backdrop
(
event.target === event.currentTarget) — clicks inside the card don't bubble-close. role="dialog"+aria-modal="true"+aria-labelledby(auto-generated unique id per instance) are set automatically; no focus-trap is implemented today — a caller chaining critical/blocking flows should be aware focus can still tab behind the modal.- Fade/scale-in animation (
0.16s ease) is skipped underprefers-reduced-motion.