Skip to content

GkOverlay

A minimal overlay for modal-style content: full-screen scrim, Teleport (default body), v-model visibility, Escape to dismiss, optional persistent mode (scrim and Escape do not close), body scroll lock while open, and tokenized z-index / scrim color.

This is intentionally smaller than Vuetify’s VOverlay: no activator slot, location/scroll strategies, router back, global stack composable, lazy hydration, or full focus-trap library. Compose with a button and v-model in your app (see demo).

When to use

Use as the lowest-level containment primitive when you need teleported layered content with scrim/escape/focus behavior but custom surface markup.

Live demo

API

Props

PropTypeDefaultDescription
modelValuebooleanfalseOpen state; use v-model
persistentbooleanfalseWhen true, scrim click and Escape do not close the overlay
tostring | HTMLElement'body'Teleport target
zIndexnumber | stringOverrides --gk-overlay-z-index when set
scrollLockbooleantrueSets document.body.style.overflow = 'hidden' while open (restored on close)
showScrimbooleantrueRenders the full-screen scrim
rolestring'dialog'ARIA role for the panel
ariaModalbooleantrueSets aria-modal="true" when true (typical for dialogs)
restoreFocusbooleantrueFocuses the first focusable in the panel on open (or the panel), restores the previous active element on close
overlayClassunknownOptional class(es) on the fixed overlay root (.gk-overlay)
contentMaxWidthstringSets --gk-overlay-content-max-width on the root (e.g. none, min(100%, 28rem)); default in CSS is min(100%, 32rem)
transitionNamestring'gk-overlay'Vue <Transition> name; use gk-bottom-sheet with GkBottomSheet (built-in styles)

Additional attributes (for example aria-labelledby, aria-describedby, id) are applied to the panel element (the element with role). defineExpose: contentRef — the panel element.

Slots

SlotDescription
defaultPanel content; clicks do not reach the scrim (@click.stop on the panel)

Events

EventPayloadDescription
update:modelValuebooleanEmitted when the overlay closes
click:outsideMouseEventEmitted when the scrim is clicked and the overlay will dismiss (not emitted when persistent is true)
afterEnterOverlay <Transition> finished entering
afterLeaveOverlay <Transition> finished leaving

Tokens

TokenPurpose
--gk-overlay-scrimScrim background (defaults via --gk-color-overlay)
--gk-overlay-z-indexDefault stacking order (2000)
--gk-overlay-content-max-widthPanel max-width (default min(100%, 32rem); GkDialog may override)

Examples

Basic

vue
<script setup lang="ts">
import { ref } from 'vue'
import { GkOverlay } from 'god-kit/vue'
</script>

<template>
  <button type="button" @click="open = true">Open</button>
  <GkOverlay
    v-model="open"
    aria-labelledby="confirm-title"
    aria-describedby="confirm-desc"
  >
    <h2 id="confirm-title">Confirm</h2>
    <p id="confirm-desc">Continue with this action?</p>
    <button type="button" @click="open = false">OK</button>
  </GkOverlay>
</template>

Advanced

vue
<GkOverlay
  v-model="open"
  :z-index="2200"
  content-max-width="min(100%, 48rem)"
  transition-name="gk-overlay"
/>

Edge case

vue
<GkOverlay
  v-model="open"
  persistent
  :show-scrim="false"
  :restore-focus="false"
/>

Accessibility notes

  • Provide aria-labelledby and aria-describedby when overlay content represents a dialog-like interaction.
  • Keep at least one focusable element in overlay content so focus management remains predictable.
  • Persistent overlays should always provide an explicit close action inside the content.

Out of scope (v1)

Activator slot, scroll/location strategies, router.back integration, global overlay stack composable, lazy hydration, and parity with Vuetify’s click-outside beyond scrim dismissal.

Released under the MIT License.