JAVASCRIPT
Using Teleport for Global Overlays
Effectively use Vue 3's `<Teleport>` component to render content, such as modals, tooltips, or notifications, into a different part of the DOM tree, avoiding z-index and overflow issues.
// GlobalModal.vue
<template>
<teleport to="body">
<div v-if="isVisible" class="global-modal-overlay">
<div class="global-modal-content">
<h3>{{ title }}</h3>
<p>{{ message }}</p>
<button @click="closeModal">Close</button>
</div>
</div>
</teleport>
</template>
<script setup>
import { ref, watch, onMounted, onUnmounted } from 'vue';
const props = defineProps({
title: String,
message: String,
modelValue: Boolean, // To control visibility with v-model
});
const emit = defineEmits(['update:modelValue']);
const isVisible = ref(props.modelValue);
watch(() => props.modelValue, (newValue) => {
isVisible.value = newValue;
toggleBodyScroll(newValue);
});
watch(isVisible, (newValue) => {
emit('update:modelValue', newValue);
toggleBodyScroll(newValue);
});
const closeModal = () => {
isVisible.value = false;
};
const toggleBodyScroll = (show) => {
if (show) {
document.body.classList.add('no-scroll');
} else {
document.body.classList.remove('no-scroll');
}
};
onMounted(() => {
toggleBodyScroll(isVisible.value);
});
onUnmounted(() => {
document.body.classList.remove('no-scroll'); // Ensure cleanup
});
</script>
<style scoped>
.global-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: 9999; /* Ensure it's on top */
}
.global-modal-content {
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
max-width: 500px;
text-align: center;
}
button {
padding: 10px 20px;
background-color: #28a745;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
margin-top: 20px;
}
button:hover {
background-color: #218838;
}
/* Global style for no-scroll */
body.no-scroll {
overflow: hidden;
}
</style>
/*
// Usage in a parent component (App.vue):
<template>
<div id="app">
<h1>App Content</h1>
<p>Some content behind the modal...</p>
<button @click="showModal = true">Open Teleported Modal</button>
<GlobalModal
v-model="showModal"
title="Important Notice"
message="This modal content is rendered in the body using Teleport, but controlled from here."
/>
</div>
</template>
<script setup>
import { ref } from 'vue';
import GlobalModal from './GlobalModal.vue';
const showModal = ref(false);
</script>
*/
How it works: The `<Teleport>` component in Vue 3 allows you to render a portion of your component's template into a different DOM node that exists outside the current component's hierarchy. This snippet demonstrates its use for a global modal. By setting `to='body'`, the modal content is moved directly under the `<body>` tag, effectively preventing common styling issues like `z-index` conflicts or `overflow: hidden` restrictions from parent elements. The modal's visibility is managed via `v-model`, showcasing how logic remains within the component while its rendering location is abstracted.