JAVASCRIPT

Programmatic Modal/Toast Management

Learn how to programmatically create and manage Vue 3 components like modals or toasts without mounting them directly in the template, enabling global overlay control.

import { createApp, ref } from 'vue';

// A simple modal component for demonstration
const ModalComponent = {
  props: {
    title: String,
    message: String,
  },
  emits: ['close'], // Declare emitted event
  template: `
    <div v-if="isVisible" class="modal-overlay">
      <div class="modal-content">
        <h3>{{ title }}</h3>
        <p>{{ message }}</p>
        <button @click="closeModal">Close</button>
      </div>
    </div>
  `,
  setup(props, { emit }) {
    const isVisible = ref(true);
    const closeModal = () => {
      isVisible.value = false;
      // After animation, remove from DOM
      setTimeout(() => emit('close'), 300); // Emit 'close'
    };
    return { isVisible, closeModal };
  },
  mounted() {
    document.body.classList.add('no-scroll'); // Prevent body scroll
  },
  beforeUnmount() {
    document.body.classList.remove('no-scroll');
  },
};

const mountComponent = (component, props) => {
  const container = document.createElement('div');
  document.body.appendChild(container);

  return new Promise(resolve => {
    // Pass a wrapper to listen for the 'close' event
    const wrappedProps = {
      ...props,
      onClose: () => { // This will be triggered when ModalComponent emits 'close'
        app.unmount();
        container.remove();
        resolve();
      }
    };

    const app = createApp(component, wrappedProps);
    app.mount(container);
  });
};

// Usage example:
// This could be a composable or a global utility
export const useModal = () => {
  const showModal = (title, message) => {
    return mountComponent(ModalComponent, { title, message });
  };
  return { showModal };
};

/*
// In a Vue component:
// App.vue
<template>
  <button @click="openMyModal">Open Modal</button>
</template>

<script setup>
import { useModal } from './modalService'; // Assuming saved as modalService.js

const { showModal } = useModal();

const openMyModal = () => {
  showModal('Welcome!', 'This is a programmatically opened modal.')
    .then(() => {
      console.log('User closed modal from component.');
    });
};
</script>

<style>
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}
.modal-content {
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}
.no-scroll {
    overflow: hidden;
}
</style>
*/
How it works: This snippet demonstrates how to programmatically mount and unmount a Vue 3 component outside of the standard app instance, useful for creating global modals, toasts, or notifications. The `createApp` function is used to instantiate a component, which is then mounted onto a newly created DOM element appended to `document.body`. A promise-based API allows for handling the modal's lifecycle, including cleanup upon closure. This approach provides fine-grained control over overlay components, ensuring they are rendered at the top of the DOM without conflicts with parent component styling or z-index.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs