@kolirt/vue-modal

Open modals from any function, stack them as needed, and style them however you want. No template boilerplate, no manual state — just call and await.
26,096 23
Install
npm install @kolirt/vue-modal
Latest Version:2.4.0
Vue:3
License:MIT
Last Updated:Jun 28, 2026
Links: GitHub  ·  npm
Maintainer: kolirt

What you get

@kolirt/vue-modal is a lightweight, headless modal package for Vue 3. It lets you open, stack, and control dialogs imperatively from any function — without registering modal components in templates or wiring open/close state by hand.

  • Open from JS/TS — trigger modals from any function and await the user's response. A single call returns a typed promise with full TypeScript inference for props and result.
  • Less template boilerplate — skip placing every modal in your templates and wiring open/close state by hand. Register one mount point and trigger any modal from code with a single call.
  • Cascading modals — open multiple modals one after another while preserving their state and context. Layer a confirmation on top of a form without losing the form's data.
  • Highly customizable — headless primitives with no imposed styles. Bring your own CSS, transitions, and animations — compose modals that fit any design system.
  • Modal groups — isolate flows with named groups — the main app stack, confirm dialogs, side panels — each rendering in its own mount point with its own queue.
  • Async components — open any Vue component, including async ones loaded on demand. Heavy modals stay out of your initial bundle and resolve through the same promise.

🤖 For AI agents

Using an AI coding agent? See AGENTS.md for a complete, de-styled reference plus a critical-rules checklist. The two most common agent mistakes are a missing <ModalContent> and z-index/stacking — both covered there.

Install

npm install @kolirt/vue-modal reka-ui
# or
yarn add @kolirt/vue-modal reka-ui
# or
pnpm add @kolirt/vue-modal reka-ui

reka-ui is a peer dependency.

Quick start

1. Register groups and install the plugin (main.ts):

The package requires every modal to belong to a registered group. Without registered groups the package can't be used at all — there's no implicit 'default'.

import { createApp } from 'vue'
import { createModal, type DefineGroups } from '@kolirt/vue-modal'
import App from './App.vue'

// (TypeScript only) Type-check every `group` reference against this list.
declare module '@kolirt/vue-modal' {
  interface ModalGroupRegistry extends DefineGroups<['default']> {}
}

const app = createApp(App)

app.use(
  createModal({
    groups: {
      // per-group behavior options — see /guide/behavior-options for the full list
      default: {}
    }
  })
)

app.mount('#app')

2. Mount a <ModalTarget> for each group (App.vue):

<script setup lang="ts">
import { ModalTarget, ModalOverlay } from '@kolirt/vue-modal'
</script>

<template>
  <RouterView />

  <ModalTarget group="default">
    <ModalOverlay class="overlay" />
  </ModalTarget>
</template>

3. Write a modal:

<!-- ConfirmDialog.vue -->
<script setup lang="ts">
import { ModalRoot, ModalContent, ModalTitle, ModalDescription, useModalContext } from '@kolirt/vue-modal'

defineOptions({ modalGroup: 'default' })

const props = defineProps<{ message: string }>()

const { close, confirm } = useModalContext<boolean>()
</script>

<template>
  <ModalRoot class="root">
    <ModalContent class="card">
      <ModalTitle>Confirm</ModalTitle>
      <ModalDescription>{{ props.message }}</ModalDescription>

      <div class="actions">
        <button @click="close()" class="btn btn--cancel">Cancel</button>
        <button @click="confirm(true)" class="btn btn--confirm">OK</button>
      </div>
    </ModalContent>
  </ModalRoot>
</template>

Styles omitted for brevity. See the first modal page for the full version with enter/exit animations.

4. Open it from anywhere:

import { openModal } from '@kolirt/vue-modal'
import ConfirmDialog from './ConfirmDialog.vue'

const ok = await openModal<boolean>(ConfirmDialog, {
  props: { message: 'Delete this project?' }
}).catch(() => false)

if (ok) {
  // user pressed OK
}

Documentation

Everything lives at kolirt.github.io/vue-modal:

  • Getting started — install, setup, your first modal
  • Concepts — architecture, imperative flow, stacking, groups, headless primitives
  • Guide — writing modals, props & results, behavior options, styling, useModal, multiple targets, async components, TypeScript
  • Recipes — confirm dialog, form with validation, lightbox, command palette, nested flows, global error modal
  • API reference — functions, components, composables, plugin, state, types
  • Migration from v1 · FAQ · Troubleshooting · Changelog

Support

License

MIT

Other packages

Check out my other projects on my GitHub profile.

Related Packages

vue-greenborn-modal-manager

Gestor de modales genérico y autocontenido para Vue 3: composable de estado (sin...

1,240 0
vue3-confirm-dialog-box

A modern, accessible confirmation dialog plugin for Vue 3 with TypeScript suppor...

929 0
@vuesimple/vs-modal

A simple vue modal. Perfect for all your modal/ dialogs scenarios.

4,747 33

Version History

Version Released License
2.4.0 MIT
2.3.0 MIT
2.2.1 MIT
2.2.0 MIT
2.1.1 MIT