JAVASCRIPT
Reusable Modal Component with Teleport and Slots
Build a versatile and accessible modal component in Vue 3, leveraging `Teleport` to render outside the DOM hierarchy and `slots` for flexible content.
// ModalDialog.vue
<template>
<Teleport to="body">
<div v-if="isOpen" class="modal-backdrop" @click.self="closeModal">
<div class="modal-content">
<header class="modal-header">
<slot name="header"><h2>Default Header</h2></slot>
<button class="close-button" @click="closeModal">X</button>
</header>
<main class="modal-body">
<slot>Default Body Content</slot>
</main>
<footer class="modal-footer">
<slot name="footer"></slot>
</footer>
</div>
</div>
</Teleport>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
isOpen: Boolean,
});
const emit = defineEmits(['close']);
const closeModal = () => {
emit('close');
};
</script>
<style scoped>
.modal-backdrop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 8px;
min-width: 300px;
max-width: 90%;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.modal-header h2 {
margin: 0;
}
.close-button {
background: none;
border: none;
font-size: 1.2em;
cursor: pointer;
}
.modal-footer {
margin-top: 15px;
text-align: right;
}
</style>
// How to use in ParentComponent.vue:
// <template>
// <div>
// <button @click="showModal = true">Open Modal</button>
// <ModalDialog :is-open="showModal" @close="showModal = false">
// <template #header><h3>Custom Modal Title</h3></template>
// <p>This is dynamic content passed through the default slot.</p>
// <template #footer>
// <button @click="showModal = false">Confirm</button>
// </template>
// </ModalDialog>
// </div>
// </template>
//
// <script setup>
// import { ref } from 'vue';
// import ModalDialog from './ModalDialog.vue';
//
// const showModal = ref(false);
// </script>
How it works: This snippet provides a robust and reusable modal component in Vue 3. It utilizes the `Teleport` component to render the modal's content directly into the `body` of the HTML document, ensuring it's not affected by parent component styling or z-index issues. `Slots` are extensively used (default, named `header`, `footer`) to allow the parent component to inject highly flexible content. The modal's visibility is controlled by the `isOpen` prop, and it emits a `close` event when the backdrop or close button is clicked, enabling easy integration and control from any parent component.