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">&times;</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.

Need help integrating this into your project?

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

Hire DigitalCodeLabs