JAVASCRIPT
Vue 3 Teleport for Creating Accessible Modals
Learn to use Vue 3's `<Teleport>` feature to render modal content directly into the document body, ensuring proper layering, accessibility, and avoiding CSS overflow issues.
// src/components/MyModal.vue
<script setup>
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
isOpen: {
type: Boolean,
default: false
},
title: {
type: String,
default: 'Modal Title'
}
});
const emit = defineEmits(['close']);
const closeModal = () => {
emit('close');
};
</script>
<template>
<Teleport to="body">
<div v-if="isOpen" class="modal-overlay fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" @click.self="closeModal">
<div class="modal-container bg-white rounded-lg shadow-xl max-w-sm w-full p-6 relative">
<h2 class="text-2xl font-bold mb-4">{{ title }}</h2>
<p class="mb-4">This content is rendered outside the component's normal DOM hierarchy, directly into the `body` element.</p>
<slot>Default modal content.</slot>
<div class="flex justify-end mt-4">
<button @click="closeModal" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors">
Close
</button>
</div>
<button @click="closeModal" class="absolute top-3 right-3 text-gray-500 hover:text-gray-700 text-xl font-bold">×</button>
</div>
</div>
</Teleport>
</template>
// src/App.vue
<script setup>
import { ref } from 'vue';
import MyModal from './components/MyModal.vue';
const showModal = ref(false);
const openModal = () => {
showModal.value = true;
};
const onCloseModal = () => {
showModal.value = false;
};
</script>
<template>
<div class="p-8 bg-gray-100 min-h-screen">
<h1 class="text-3xl font-bold mb-6">Vue 3 Teleport Example</h1>
<p class="mb-4">Click the button below to open a modal.</p>
<button @click="openModal" class="px-6 py-3 bg-green-500 text-white text-lg rounded-lg hover:bg-green-600 transition-colors">
Open Modal
</button>
<MyModal :is-open="showModal" title="Important Notification" @close="onCloseModal">
<p>You have new messages in your inbox!</p>
</MyModal>
<div class="mt-8 p-6 bg-white rounded shadow-md">
<h2 class="text-xl font-bold mb-2">Main Page Content</h2>
<p>This is the main content of your application.</p>
<p>The modal will appear on top of this content, no matter where its component is placed in the DOM tree, thanks to Teleport.</p>
</div>
</div>
</template>
How it works: This snippet illustrates the use of Vue 3's `<Teleport>` component to create an accessible modal. By specifying `to="body"`, the modal's content is rendered directly as a child of the `body` element in the DOM, regardless of where the `<MyModal>` component is used in the application's component tree. This prevents common z-index, overflow, and styling issues often encountered with modals and overlays, ensuring they always appear on top and are correctly positioned.