Overview
The Modal block is an overlay dialog that opens above the page and blocks interaction with everything behind it. It has two variants: Card (compose Header, Body, and Footer slots) and Page (embeds an existing page with inputs). A modal starts closed with no space in the page layout. Open it with the Control modal action or the showModal method.
Note: New Card modals arrive as 400×400 px with rounded corners, a "Modal Title" header with close button, and an empty body.
For a panel that slides in from the edge of the page and can leave the rest of the page interactive, see Drawer.
Modal Variants
| Variant | What it shows | Use case |
| Card | Three slots: Header, Body, Footer — composed from blocks you drop in | Confirmation dialogs, short forms, custom composed dialogs |
| Page | Embeds an existing app page with Page Inputs you bind | Reusing an edit or detail page as a dialog |
Content Properties
| Property | Type | Default | Appears When | Description |
| variant | "card" | "page" | card | Always | Card: compose slots. Page: embed an existing page |
| pageId | page reference | — | variant = page | The app page to embed. Only static-path pages are offered |
| inputs | object (bindable) | — | variant = page | Values passed as page inputs to the embedded page |
| slots | header, body, footer | Header with title + close; empty body; empty footer | variant = card | The three layout areas of a Card modal |
| hideOnEscape | boolean | true (web) | Web only | Close modal when user presses Escape key |
| hideOnClickOutside | boolean | true | Always | Close modal when user clicks the dimmed backdrop |
| interactions | event list | — | Always | On Open / On Close event handlers |
| permissions | permission rule | — | Always | Restrict who can see or use the modal |
Appearance Properties
| Property | Type | Default | Description |
| width | px or % | 400 px | Dialog width. Set both to 100% for full-screen |
| height | px or % | 400 px | Dialog height. Set both to 100% for full-screen |
| styles | style set | rounded corners | Stroke and radius of the dialog box |
| visibility | condition | — | Show/hide the whole block |
| showBlurBackdrop (mobile) | boolean | — | Mobile apps only. Shows a blur effect behind the modal |
Events
| Event | Trigger |
| On Open | The modal opens |
| On Close | The modal closes (via any method: action, method, Escape, backdrop, or close button) |
Methods
| Method | Parameters | What it does |
showModal | — | Opens the modal |
hideModal | — | Closes the modal |
Call these via a Control block method action or the Control modal action.
Exposed State
| Binding | Type | Description |
{{ id.state.open }} | boolean | Whether the modal is currently open |
Behaviors & Gotchas
Warning: The header close button always closes: Hide on Escape and Hide on Click Outside only control those two dismissal paths. The built-in close button in the header closes the modal regardless of both toggles.
Note: Width and Height at 100% = full-screen: When both are set to 100% (or "full"), the dialog switches to a dedicated full-screen layout instead of a centered box.
Note: Page modal loading/error renders inside the dialog: The embedded page's loading spinner (or error) renders inside the open modal frame, not behind it.
Note: Embedded page events surface on the modal: Events emitted by the embedded page bubble up to the modal's Interactions, enabling the inner page to close the modal or refresh a table on the host page.
Note: Hide on Escape doesn't exist on mobile: Mobile app builders omit this toggle (no Escape key). They gain Show Blur Backdrop instead.
Examples & Patterns
Modal vs. Drawer
Both are overlays with Card and Page variants. Reach for a Modal when the user must deal with the dialog before doing anything else. Reach for a Drawer when the panel belongs at the edge of the page, or when the rest of the page should stay usable.
| Feature | Modal | Drawer |
| Position | Centered over page | Edge of page (left, right, bottom) |
| Backdrop | Always blocks interaction behind it | Optional, configurable |
| Default size | 400×400 px | 38.2% wide (desktop), 61.8% tall (mobile) |
| Full-screen mode | Set width+height to 100% | Not applicable |
| Page variant | Yes (embeds another page) | Yes (embeds another page) |
| Exposed state | state.open | None |
| Mobile default | Same centered dialog | Bottom sheet at 61.8% height |
| Multiple open | Standard: one centered | One at a time (second closes first) |
| Dismiss methods | hideModal(), Escape, click-outside, close button | hideDrawer(), click-outside, drag-down (mobile) |
Related Blocks
| Block | Relationship |
| Drawer | Edge-anchored overlay panel — use when the page behind may stay interactive |
| Bottom Sheet | Purpose-built swipeable bottom panel for mobile |
| Mobile Contextual Dialog | Small anchored popover for in-context menus |
| Stack | The default container inside each slot (header/body/footer) |
| Form / Table | Typical modal contents and triggers |
Frequently Asked Questions
How do I make a Modal full-screen?
Set both Width and Height to 100% (or "full") in the Modal's Appearance panel. The dialog switches to a dedicated full-screen layout instead of a centered box.
I turned off Hide on Escape and Hide on Click Outside — why can the user still dismiss the Modal?
Those two toggles only control those two dismissal paths. The built-in close button in the Card header closes the modal regardless of both settings. Remove or replace the header slot content if the modal must only close through your own actions.
Can I read whether a Modal is currently open?
Yes. The Modal exposes {{ id.state.open }}, a boolean you can bind anywhere on the page — for example, to drive a conditional or to disable the button that opened it.
Can I embed a page with a dynamic URL parameter in a Modal?
No. Only pages with static paths can be embedded. Pages with dynamic URL segments (like /records/:id) are not available in the page picker. Pass the dynamic value (like a record ID) through Page Inputs instead.
How does an embedded page tell the Modal to close?
Events emitted by the embedded page bubble up to the Modal's Interactions. Handle the page's event there and run Control modal with hide — the same handler can also refresh a table on the host page.