Skip to content

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 Drawer instead 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

VariantWhen to use it
Standard ModalFocused tasks — forms, edit details, review long content. Large enough for rich content without leaving the page.
Modal fullscreenGenuinely immersive editors and multi-step flows where the page behind would be a distraction. Reserve for complex workflows.
ConfirmModalIrreversible or destructive actions. Keep it short — one question, one consequence statement, two buttons.
DrawerSupplementary 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).

PropTypeDefaultDescription
isOpenbooleanfalseTwo-way bound open state. Use with v-model:is-open.
titlestringrequiredHeader title.
subtitlestringOptional second line under the title.
icon'exclamation-circle' | 'information-circle' | 'check-circle' | 'exclamation-triangle'Status icon shown next to the title.
fullscreenbooleanfalseRender at full viewport size.
staticbooleanfalseDisable dismiss-on-overlay-click.
SlotSlot propsDescription
default{ close }Modal body — typically wraps <ModalContent> and <ModalFooter>. The close slot prop is a function you can call to dismiss.
EventDescription
closeFired when the modal is dismissed (close button, overlay click, or Escape).

ConfirmModal — Props

PropTypeDefaultDescription
isOpenbooleanfalseTwo-way bound open state. Use with v-model:is-open.
titlestringtranslated 'general.are-you-sure'Header title.
messagestringtranslated 'general.action-irreversible'Body paragraph.
subtitlestringOptional second line under the title.
staticbooleanfalseDisable dismiss-on-overlay-click.
buttonsConfirmModalButton[]Custom buttons (overrides the default Confirm + Cancel). See "Custom buttons" above.

ConfirmModalButton extends ButtonProps and adds:

FieldTypeDescription
labelstringButton text.
position'left' | 'right'Where the button sits in the footer (right is the primary side).
onClick(handlers: { confirm: () => void, cancel: () => void }) => voidClick handler. Call confirm() or cancel() to close the modal and resolve the useConfirmModal promise.

ConfirmModal — Events

EventDescription
confirmDefault confirm button clicked. (Custom buttons emit through their onClick handlers instead.)
cancelUser dismissed (Cancel button, overlay click, Escape, or close button).