Modal
Centered overlay dialog rendered via portal. Modals interrupt the page to put a focused task or decision in front of the user. Reach for them when the user genuinely needs to stop and respond — not as a passive feedback channel.
html
<Button @click="isOpen = true">Open modal</Button>
<Modal v-model:is-open="isOpen" title="Basic modal">
<ModalContent>
<p>Modal body content goes inside <code>ModalContent</code>.</p>
</ModalContent>
<ModalFooter>
<Button variant="secondary" @click="isOpen = false">Cancel</Button>
<Button @click="isOpen = false">Save</Button>
</ModalFooter>
</Modal>Aurora's Modal is the controlled wrapper — pair with ModalContent for the body and ModalFooter for the action row. For yes/no confirmations, use ConfirmModal directly or the programmatic helper useConfirmModal().
When to reach for a modal
- Focused tasks — a form, a small wizard, or editing details that need full attention
- Irreversible actions — destructive operations that need explicit confirmation before proceeding
- Extended side context — use
Drawerinstead when you want supplementary content the user can reference while still seeing the page
When not to use a modal
- Simple success / error feedback ("Saved", "Couldn't reach the server") → use
Toaster. Modals interrupt; toasts inform. - Content the user references repeatedly — keep that on the page. Modals close, and re-opening them is friction.
- Stacking multiple modals — only one modal should be visible at a time.
Picking the right shape
| Variant | When to use it |
|---|---|
Standard Modal | Focused tasks — forms, edit details, review long content. Large enough for rich content without leaving the page. |
Modal fullscreen | Genuinely immersive editors and multi-step flows where the page behind would be a distraction. Reserve for complex workflows. |
ConfirmModal | Irreversible or destructive actions. Keep it short — one question, one consequence statement, two buttons. |
Drawer | Supplementary context (details, filters, activity log) the user can reference without leaving the page. |
With subtitle
html
<Modal v-model:is-open="isOpen" title="Saved view created" subtitle="You can rename it from the views menu.">
<ModalContent>…</ModalContent>
<ModalFooter><Button>Done</Button></ModalFooter>
</Modal>With icon
The icon prop accepts one of four status icons that match aurora's status semantics.
html
<Modal v-model:is-open="isOpen" title="Are you sure?" icon="exclamation-triangle">
<ModalContent>
<p>This action will affect 12 assets.</p>
</ModalContent>
<ModalFooter>
<Button variant="secondary" @click="isOpen = false">Cancel</Button>
<Button danger @click="isOpen = false">Continue</Button>
</ModalFooter>
</Modal>Fullscreen
html
<Modal v-model:is-open="isOpen" title="Fullscreen modal" fullscreen>…</Modal>ConfirmModal — declarative
Use ConfirmModal for irreversible or destructive actions. Keep the message short and consequence-first — "Delete building? All associated ESG data will be permanently removed." Pair a tertiary Cancel with a danger confirm button so the consequence is visually loud.
Render a ConfirmModal directly when you need it embedded in your component tree (rather than fired imperatively).
html
<ConfirmModal
v-model:is-open="isOpen"
title="Delete report?"
message="This action is irreversible."
@confirm="onDelete"
@cancel="isOpen = false"
/>All props are optional. Without title, ConfirmModal falls back to the translated default 'general.are-you-sure'; without message, it falls back to 'general.action-irreversible'.
ConfirmModal — programmatic
For one-off confirmations (e.g. inside an event handler), use useConfirmModal to get a promise-based API. No template authoring required.
ts
import { useConfirmModal } from '@scaler-tech/aurora/modal'
const { confirm } = useConfirmModal()
async function onDelete() {
const ok = await confirm({
title: 'Delete this report?',
message: 'This action is irreversible.',
})
if (ok) {
// perform the delete
}
}confirm() returns a Promise<boolean> — true for confirm, false for cancel.
Custom buttons
For non-default copy or styling (e.g. destructive Delete button), pass buttons. Each button extends ButtonProps (so variant, danger, size, etc. all work) plus three required fields: label, position, onClick. The onClick handler receives { confirm, cancel } callbacks.
ts
const ok = await confirm({
title: 'Delete this report?',
message: 'All saved versions will be removed.',
buttons: [
{ label: 'Cancel', position: 'left', variant: 'tertiary', onClick: ({ cancel }) => cancel() },
{ label: 'Delete', position: 'right', variant: 'primary', danger: true, onClick: ({ confirm }) => confirm() },
],
})position: 'left' and position: 'right' group buttons in the footer (right-aligned on desktop, primary actions on the right).
Modal — Props
| Prop | Type | Default | Description |
|---|---|---|---|
isOpen | boolean | false | Two-way bound open state. Use with v-model:is-open. |
title | string | required | Header title. |
subtitle | string | — | Optional second line under the title. |
icon | 'exclamation-circle' | 'information-circle' | 'check-circle' | 'exclamation-triangle' | — | Status icon shown next to the title. |
fullscreen | boolean | false | Render at full viewport size. |
static | boolean | false | Disable dismiss-on-overlay-click. |
Modal — Slots
| Slot | Slot props | Description |
|---|---|---|
default | { close } | Modal body — typically wraps <ModalContent> and <ModalFooter>. The close slot prop is a function you can call to dismiss. |
Modal — Emits
| Event | Description |
|---|---|
close | Fired when the modal is dismissed (close button, overlay click, or Escape). |
ConfirmModal — Props
| Prop | Type | Default | Description |
|---|---|---|---|
isOpen | boolean | false | Two-way bound open state. Use with v-model:is-open. |
title | string | translated 'general.are-you-sure' | Header title. |
message | string | translated 'general.action-irreversible' | Body paragraph. |
subtitle | string | — | Optional second line under the title. |
static | boolean | false | Disable dismiss-on-overlay-click. |
buttons | ConfirmModalButton[] | — | Custom buttons (overrides the default Confirm + Cancel). See "Custom buttons" above. |
ConfirmModalButton extends ButtonProps and adds:
| Field | Type | Description |
|---|---|---|
label | string | Button text. |
position | 'left' | 'right' | Where the button sits in the footer (right is the primary side). |
onClick | (handlers: { confirm: () => void, cancel: () => void }) => void | Click handler. Call confirm() or cancel() to close the modal and resolve the useConfirmModal promise. |
ConfirmModal — Events
| Event | Description |
|---|---|
confirm | Default confirm button clicked. (Custom buttons emit through their onClick handlers instead.) |
cancel | User dismissed (Cancel button, overlay click, Escape, or close button). |