Overlay
Overlay
<ModalOverlay> is the optional dimming layer rendered inside <ModalTarget>. It mounts whenever the group has at least one active modal and unmounts after the last one closes — driven by <Presence> from reka-ui, so enter/exit animations are respected.
The overlay is purely visual by default: position: absolute; inset: 0; pointer-events: none. Clicks pass through to [data-modal-region], which is where the package detects "click outside content" to close the topmost modal.
Minimal usage
<script setup lang="ts">
import { ModalOverlay, ModalTarget } from '@kolirt/vue-modal'
</script>
<template>
<ModalTarget group="default">
<ModalOverlay class="bg-black/50" />
</ModalTarget>
</template>
You can omit <ModalOverlay> entirely — modals will render without a backdrop.
Customizing with the default slot
The overlay exposes a default slot. Use it to layer decorative elements on top of the base dimming color: gradients, noise textures, blur layers, branding watermarks, animated backgrounds.
<ModalOverlay class="overlay">
<div class="overlay__noise" />
<div class="overlay__gradient" />
</ModalOverlay>
.overlay {
background: rgba(0, 0, 0, 0.55);
}
.overlay__noise {
position: absolute;
inset: 0;
background: url('/noise.png') repeat;
opacity: 0.08;
mix-blend-mode: overlay;
}
.overlay__gradient {
position: absolute;
inset: 0;
background: radial-gradient(circle at center, transparent 0%, rgba(0, 0, 0, 0.4) 100%);
}
Pointer events
The root [data-modal-overlay] is pointer-events: none. Slotted children inherit that — they're decorative and won't intercept clicks, which preserves the "click overlay to close" behavior driven by [data-modal-region].
If a slotted element must receive interaction (e.g. a logo link, a watermark with a tooltip), enable pointer events on that specific element:
.overlay__logo {
pointer-events: auto;
}
Keep this rare. Interactive controls (close buttons, action bars) usually belong inside <ModalContent> so they participate in focus management and don't compete with the click-outside-to-close behavior.
Data attributes for styling
| Attribute | When present |
|---|---|
[data-modal-overlay] | Always — the anchor for CSS rules |
data-state="open" | Group has at least one active modal |
data-state="closed" | Last modal in the group is exiting |
data-instant | Topmost modal was opened with instantEnter — overlay enter animation should be suppressed |
[data-modal-overlay] {
background: rgba(0, 0, 0, 0.5);
transition: opacity 200ms ease;
}
[data-modal-overlay][data-state='open'] {
opacity: 1;
}
[data-modal-overlay][data-state='closed'] {
opacity: 0;
}
The package ships a built-in rule that disables the overlay enter animation while data-instant is set on data-state="open", so instantEnter modals don't get a fading backdrop. Exit animations still run normally.
Per-group overlays
Each <ModalTarget> mounts its own <ModalOverlay>. Different groups can have different backdrops, opacities, or animations without conflicting with each other:
<ModalTarget group="default">
<ModalOverlay class="bg-black/40" />
</ModalTarget>
<ModalTarget group="confirm">
<ModalOverlay class="bg-black/70 backdrop-blur-sm" />
</ModalTarget>
See Multiple targets for stacking, z-index, and per-target overrides.
Errors
<ModalOverlay> must be a descendant of <ModalTarget>. Mounting it standalone throws:
[@kolirt/vue-modal] <ModalOverlay> must be used inside <ModalTarget>.
