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.