npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dsplce-co/vue-modal

v0.4.3

Published

Utility library for displaying modals in Vue

Readme

We're dsplce.co, check out our work on our website: dsplce.co 🖤

vue-modal

Vue version TypeScript version NPM downloads NPM unpacked size License NPM version

🧩 Modal composable for Vue — A minimal and type-safe framework for modals in Vue.js applications.


🖤 Features

✅ Type-safe modal system with generics ✅ Automatic prop requirement inference ✅ Close your modals from anywhere with composables ✅ ARIA-compliant ✅ Esc key handling ✅ Click outside to close ✅ Teleport-based rendering with proper z-index ✅ Built-in smooth transitions ✅ Zero external CSS dependencies ✅ Vue 3 Composition API ready


📦 Installation

Add to your package.json:

npm install @dsplce-co/vue-modal
# or
yarn add @dsplce-co/vue-modal
# or
pnpm add @dsplce-co/vue-modal

This package requires Vue 3.


🧪 Usage

1. Set up the plugin

Install the Vue Modal plugin in your main application file to enable global modal state management:

import { createApp } from 'vue';
import VueModalPlugin from '@dsplce-co/vue-modal';
import App from './App.vue';

const app = createApp(App);

app.use(VueModalPlugin);
app.mount('#app');

2. Add modal collector

Add the ModalCollector component to your app root to enable modal rendering. This will manage the rendering of all modals in a single location.

<template>
  <div id="app">
    <router-view />

    <users-view /> <!-- We'll get to this in a moment -->

    <modal-collector />
  </div>
</template>

<script setup>
import { ModalCollector } from '@dsplce-co/vue-modal';
</script>

3. Create modal component

Imagine in your application there is a user list view, and you want to add the functionality to delete a user. You decide a confirmation dialog would come in handy.

In vue-modal, your modal component can be any regular Vue component. It receives props as usual and can emit a close event:

<template>
  <div class="confirmation-modal">
    <h2>Confirm Action</h2>
    <p>Are you sure you want to delete {{ user.name }}?</p>

    <div class="confirmation-modal__actions">
      <button @click="$emit('close')">Cancel</button>
      <button @click="confirmDelete">Confirm</button>
    </div>
  </div>
</template>

<script setup lang="ts">
import type { User } from './UsersView.vue';

const props = defineProps({
  user: {
    type: Object as () => User,
    required: true,
  },
  onConfirm: {
    type: Function,
    required: true,
  },
});

const emit = defineEmits(['close']);

const confirmDelete = () => {
  props.onConfirm(props.user.id);
  emit('close');
};
</script>

<style>
.confirmation-modal {
  background: white;
  padding: 2rem;
  max-width: 400px;
  width: 100%;
}

.confirmation-modal__actions {
  display: flex;
  gap: .5rem;
  margin-top: 1.5rem;
  justify-content: flex-end;
}

.confirmation-modal__actions button {
  padding: 0.5rem 1rem;
  border: none;
  cursor: pointer;
}

.confirmation-modal__actions button:first-child {
  background: #e5e7eb;
}

.confirmation-modal__actions button:last-child {
  background: #ff3b89;
  color: white;
}
</style>

4. Use the modal

Now that you've defined the confirmation modal, let's use it with the useModal composable:

<template>
  <div class="users-view">
    <!-- ❗ Notice the ConfirmationModal is not mounted directly -->
    <!-- anywhere — it is the ModalCollector's job to render modals -->
    <ul>
      <li v-for="user in users" :key="user.id">
        {{ user.name }}
        <button @click="onDelete(user)">Delete</button>
      </li>
    </ul>
  </div>
</template>

<script setup lang="ts">
import { useModal } from '@dsplce-co/vue-modal';
import { ref } from 'vue';
import ConfirmationModal from './ConfirmationModal.vue';

export type User = {
  id: string;
  name: string;
};

const users = ref<User[]>([
  { id: '1', name: 'Walter White' },
  { id: '2', name: 'Hank Schrader' },
]);

const deleteUser = (id) => {
  console.log('Deleting user with id:', id);
  // Your deletion logic here
};

// Register the modal
const modal = useModal(ConfirmationModal);

const onDelete = (user: User) => {
  // Open modal with required props
  modal.open({
    user,
    onConfirm: () => deleteUser(user.id),
  });
};
</script>

📐 API reference

Plugin setup

VueModalPlugin

Vue plugin that sets up global modal state management.

import { createApp } from 'vue';
import VueModalPlugin from '@dsplce-co/vue-modal';

app.use(VueModalPlugin);

Components

ModalCollector

Component that manages modal rendering using Vue's teleport system.

<template>
  <ModalCollector />
</template>

Composables

useModal

Creates a typed modal controller for a specific component:

import { useModal } from '@dsplce-co/vue-modal';

const modal = useModal(YourModalComponent);

Returns an object with:

  • open(props) - Opens the modal with provided props
  • close() - Closes the modal

Type safety: The composable automatically infers whether props are required or optional based on your component's prop definitions:

// If modal has required props
modal.open({ requiredProp: 'value' }); // ✅ TypeScript enforces this

// If modal has only optional props
modal.open(); // ✅ Props can be omitted
modal.open({ optionalProp: 'value' }); // ✅ Or provided

Modal component guidelines

Your modal components should:

  1. Emit close event: Use $emit('close') or defineEmits(['close']) to enable closing
  2. Handle props: Define props normally using defineProps or props option
  3. Style appropriately: Apply styles for the modal content (overlay is handled by the collector)
<template>
  <div class="my-modal">
    <h2>{{ title }}</h2>
    <button @click="$emit('close')">Close</button>
  </div>
</template>

<script setup lang="ts">
defineProps({
  title: {
    type: String,
    required: true,
  },
});

defineEmits(['close']);
</script>

Modal features

  • Accessibility: Proper ARIA attributes and focus management
  • Keyboard Navigation: Esc key closes modal automatically
  • Click Outside: Click outside the modal content to close
  • Portal Rendering: Modals render at the body level using Vue's teleport
  • Single Modal: Only one modal can be open at a time (why would you want to show more than one modal at a time? 🤨)
  • Transitions: Smooth fade in/out animations
  • Responsive: Full viewport coverage with centered content
  • Backdrop: Semi-transparent backdrop with blur effect

🎨 Styling

The library provides minimal base styles for the overlay and positioning. You're responsible for styling your modal components.


🔧 Advanced usage

Custom modal overlay and wrapper

You can customise how modals are rendered by using the ModalCollector's slot:

<ModalCollector v-slot="{ component, payload, close }">
  <div v-if="component !== null" class="custom-overlay">
    <div class="custom-modal-container">
      <div class="modal-header">
        <button @click="close">×</button>
      </div>

      <component :is="component" v-bind="payload" @close="close" />
    </div>
  </div>
</ModalCollector>

📁 Repo & contributions

📦 Package: @dsplce-co/vue-modal 🛠️ Repo: github.com/dsplce-co/vue-modal

Contributions, issues, ideas? Hit us up 🖤


🔒 License

MIT or Apache-2.0, at your option.