Api

Components

ModalTarget, ModalRoot, ModalContent, ModalTitle, ModalDescription, ModalOverlay.

Components

<ModalTarget>

The host where modals of one group are rendered. Mount one per group.

Props

interface ModalTargetProps extends ModalBehaviorOptions {
  group: ModalGroup // required, type-checked against ModalGroupRegistry
  enableInteractOutside?: boolean
  disableCloseOnInteractOutside?: boolean
  disableCloseOnInteractOverlay?: boolean
  disableLockBodyScroll?: boolean
  disableCloseOnEscape?: boolean
}

See Behavior options for what each flag does.

Slots

  • default — user content placed inside [data-modal-region]. Typically <ModalOverlay>. Active modals are rendered alongside automatically.

Emitted events

None.

Data attributes

  • [data-modal-region] — root element. position: fixed; inset: 0; pointer-events: none.

See Types for ModalTargetProps and ModalBehaviorOptions.


<ModalRoot>

Per-modal wrapper. Owns DialogRoot from reka-ui, computes dataState/instantEnter, exposes close intents to <ModalContent>.

Must contain <ModalContent> — without it, exit animations never finalize.

Props

Empty interface — all behavior options live on <ModalTarget> or in createModal({ groups }).

Slots

  • default — your modal markup. Must contain <ModalContent>.

Emitted events

None.

Throws

  • If used outside a modal opened via openModal/useModal. Exact message: [@kolirt/vue-modal] <ModalRoot> must be used inside a modal opened via openModal/useModal.
  • If rendered outside a <ModalTarget> tree. Exact message: [@kolirt/vue-modal] <ModalRoot> must be rendered inside a <ModalTarget> tree.

Data attributes

  • [data-modal-root] — wrapper div rendered inside reka-ui's DialogRoot. position: absolute; inset: 0; pointer-events: auto. inheritAttrs: false; $attrs (including class, style) forward to this div.

<ModalContent>

Required inside <ModalRoot>. Wraps reka-ui's DialogContent — focus trap and presence management.

Props

None. inheritAttrs: false; $attrs (including class, style, aria-*) forward to the inner DialogContent.

Slots

  • default — card markup.

Emitted events

None.

Data attributes

  • [data-modal-content] — root element.
  • data-state="open" | "closed" — animation hook.
  • data-instant="" — present for the lifetime of a modal opened with instantEnter: true. Bundled CSS rule scoped to [data-state="open"] suppresses the enter animation; the close animation still runs because suppression doesn't apply when data-state="closed".

Throws

  • If used outside <ModalRoot>. Exact message: [@kolirt/vue-modal] <ModalContent> must be used inside <ModalRoot>.

<ModalTitle>

Optional. Wraps reka-ui's DialogTitle. Auto-wires aria-labelledby on DialogContent.

<ModalContent>
  <ModalTitle class="text-lg font-bold">Confirm</ModalTitle>
</ModalContent>

Props

None.

Slots

  • default — title text or markup.

Emitted events

None.

Data attributes

  • [data-modal-title] — anchor element.

Without a title, reka-ui logs an accessibility warning. Use <VisuallyHidden> from reka-ui if you don't want a visible heading.


<ModalDescription>

Optional. Wraps reka-ui's DialogDescription. Auto-wires aria-describedby.

<ModalContent>
  <ModalTitle>Confirm</ModalTitle>
  <ModalDescription>This action cannot be undone.</ModalDescription>
</ModalContent>

Props

None.

Slots

  • default — description text or markup.

Emitted events

None.

Data attributes

  • [data-modal-description] — anchor element.

If you don't include a description, suppress reka-ui's warning by passing :aria-describedby="undefined" on <ModalContent>.


<ModalOverlay>

Optional. The dimming layer. Place inside <ModalTarget> slot.

<ModalTarget group="default">
  <ModalOverlay class="bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out" />
</ModalTarget>

Props

None. inheritAttrs: false; $attrs flow to the inner [data-modal-overlay] div.

Slots

  • default — optional content rendered inside [data-modal-overlay]. Use it to add decorative elements (blur layers, gradients, noise textures, branding watermarks, animated backgrounds) on top of the dimming layer. The overlay itself has pointer-events: none by default — set pointer-events: auto on slotted elements that need to receive interaction.
<ModalOverlay class="bg-black/50">
  <div class="overlay-noise" />
  <div class="overlay-gradient" />
</ModalOverlay>

Emitted events

None.

Data attributes

  • [data-modal-overlay] — anchor.
  • data-state="open" | "closed" — driven by group activity (whether any modal is mounted). Distinct from <ModalContent>'s data-state which tracks individual modal visibility.

Throws

  • If used outside <ModalTarget>. Exact message: [@kolirt/vue-modal] <ModalOverlay> must be used inside <ModalTarget>.
Copyright © 2026