JAVASCRIPT

Manage Overlays with Vue 3 Teleport

Learn how to use Vue 3's Teleport component to render modal dialogs, tooltips, or notifications outside the component's DOM hierarchy, solving common styling issues.

// components/ModalComponent.vue
<template>
  <teleport to="body">
    <div v-if="isOpen" class="modal-backdrop" @click.self="closeModal">
      <div class="modal-content">
        <header class="modal-header">
          <h3>{{ title }}</h3>
          <button @click="closeModal" class="close-button">&times;</button>
        </header>
        <div class="modal-body">
          <slot>Default modal content.</slot>
        </div>
        <footer class="modal-footer">
          <slot name="footer">
            <button @click="closeModal">Close</button>
          </slot>
        </footer>
      </div>
    </div>
  </teleport>
</template>

<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>

<style scoped>
.modal-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.modal-content {
  background-color: white;
  padding: 20px;
  border-radius: 8px;
  min-width: 300px;
  max-width: 80%;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  position: relative;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
  border-bottom: 1px solid #eee;
  padding-bottom: 10px;
}

.close-button {
  background: none;
  border: none;
  font-size: 1.5rem;
  cursor: pointer;
}

.modal-footer {
  border-top: 1px solid #eee;
  padding-top: 10px;
  margin-top: 15px;
  display: flex;
  justify-content: flex-end;
}
</style>

// App.vue
<template>
  <div>
    <h1>My App Content</h1>
    <button @click="showModal = true">Open Modal</button>

    <ModalComponent :is-open="showModal" title="Important Notification" @close="showModal = false">
      <p>This content is rendered inside the modal body.</p>
      <p>Even though the modal component is nested here, its content is teleported to the body!</p>
      <template #footer>
        <button @click="showModal = false" style="background-color: #007bff; color: white; border: none; padding: 8px 15px; border-radius: 4px; cursor: pointer;">
          Confirm
        </button>
      </template>
    </ModalComponent>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import ModalComponent from './components/ModalComponent.vue';

const showModal = ref(false);
</script>
How it works: This snippet demonstrates Vue 3's `Teleport` component to create a modal dialog. Even though `ModalComponent` is a child of `App.vue`, `Teleport` moves its content to a specified target (in this case, `body`) in the DOM. This is crucial for managing z-index, avoiding overflow issues, and ensuring overlays are rendered correctly regardless of their parent's styling context.

Need help integrating this into your project?

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

Hire DigitalCodeLabs