Skip to content

Modal

Overlay dialog for confirmations, destructive actions, and critical decisions. Forces user focus while the rest of the page is deactivated.

Demo

Standard (scale)

Persistent (kræver handling)

Transitions

Installation

vue
<script setup>
import { GTModal } from '@grundtone/vue';
</script>

In Nuxt, GTModal is auto-imported.

When to use

Use a modal when the user must see and respond to specific content before continuing.

Do not use for page content, long text, multi-field forms, or as a default pattern. Keep content short — no scrolling inside the modal.

Usage

Standard

vue
<script setup>
import { ref } from 'vue';
const showModal = ref(false);
</script>

<template>
  <GTButton @click="showModal = true">Åbn modal</GTButton>

  <GTModal v-model:open="showModal" title="Bekræft handling">
    <p>Er du sikker på at du vil fortsætte?</p>
    <template #footer>
      <GTButton variant="outlined" size="sm" @click="showModal = false">Annuller</GTButton>
      <GTButton variant="primary" size="sm" @click="showModal = false">Bekræft</GTButton>
    </template>
  </GTModal>
</template>

Persistent (kræver handling)

Cannot be closed with Escape, backdrop click, or close button. User must click an action button.

vue
<GTModal v-model:open="showDelete" title="Slet konto?" persistent>
  <p>Denne handling kan ikke fortrydes.</p>
  <template #footer>
    <GTButton variant="outlined" size="sm" @click="showDelete = false">Annuller</GTButton>
    <GTButton variant="negative" size="sm" @click="deleteAccount">Slet konto</GTButton>
  </template>
</GTModal>

Transitions

vue
<GTModal transition="fade" ... />
<GTModal transition="scale" ... />      <!-- default -->
<GTModal transition="slide-up" ... />   <!-- bottom sheet feel -->
<GTModal transition="slide-down" ... />
<GTModal transition="slide-right" ... />
<GTModal transition="none" ... />

Props

PropTypeDefaultDescription
openbooleanControls visibility (v-model:open)
titlestringDialog title (required)
persistentbooleanfalseOnly closeable via action buttons
transitionModalTransition'scale'Enter/exit animation
ariaLabelstringScreen reader label (defaults to title)

ModalTransition

'fade' | 'scale' | 'slide-up' | 'slide-down' | 'slide-right' | 'none'

Slots

SlotDescription
defaultModal body content
footerAction buttons

Events

EventPayloadDescription
update:openbooleanv-model binding
closeEmitted when modal closes

Behavior

  • Focus trap: Tab/Shift+Tab cycles within the modal
  • Focus restore: Focus returns to the trigger element on close
  • Scroll lock: Body scroll disabled with scrollbar compensation
  • Escape: Closes the modal (standard variant)
  • Backdrop click: Closes the modal (standard variant)
  • Teleport: Rendered in <body> for z-index isolation

Accessibility

  • role="dialog" with aria-modal="true" on the dialog
  • aria-labelledby points to the title
  • Focus trapped inside dialog
  • Escape key closes (standard variant)
  • Body scroll locked while open

CSS Classes

ClassDescription
gt-modalFixed backdrop overlay
gt-modal__dialogCentered dialog container
gt-modal__headerTitle + close button
gt-modal__titleHeading text
gt-modal__closeClose button
gt-modal__bodyContent area
gt-modal__footerAction buttons

See Modal (Design System) for full CSS reference.