← Back to all snippets
JAVASCRIPT

Implementing a Reusable Teleported Modal Component

Create a robust and accessible modal in Vue 3 using the <Teleport> component to render content outside the app's DOM tree, ensuring proper z-indexing and reusability.

<!-- Modal.vue -->
<template>
  <teleport to="body">
    <div v-if="isOpen" class="modal-backdrop" @click.self="closeModal">
      <div class="modal-content">
        <button class="modal-close" @click="closeModal">×</button>
        <slot></slot>
      </div>
    </div>
  </teleport>
</template>

<script setup>
import { ref } from 'vue';

const isOpen = ref(false);

const openModal = () => {
  isOpen.value = true;
  document.body.style.overflow = 'hidden'; // Prevent scrolling background
};

const closeModal = () => {
  isOpen.value = false;
  document.body.style.overflow = '';
};

defineExpose({
  openModal,
  closeModal
});
</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: white;
  padding: 20px;
  border-radius: 8px;
  min-width: 300px;
  max-width: 90%;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  position: relative;
}

.modal-close {
  position: absolute;
  top: 10px;
  right: 10px;
  border: none;
  background: none;
  font-size: 1.5em;
  cursor: pointer;
}
</style>

<!-- App.vue (Usage Example) -->
<template>
  <div>
    <button @click="modalRef.openModal()">Open Modal</button>
    <Modal ref="modalRef">
      <h2>Hello from the Modal!</h2>
      <p>This content is teleported to the body.</p>
    </Modal>
  </div>
</template>

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

const modalRef = ref(null);
</script>
How it works: This snippet demonstrates creating a reusable modal component using Vue 3's built-in `<Teleport>` component. The `<Teleport to="body">` tag ensures that the modal's content is rendered directly into the `<body>` of the HTML document, outside the typical Vue app's DOM tree. This approach effectively resolves common z-index issues, ensures accessibility, and prevents styles from parent components from inadvertently affecting the modal. The component uses `ref` for its internal state (`isOpen`) and `defineExpose` to allow a parent component to programmatically open and close it.

Need help integrating this into your project?

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

Hire DigitalCodeLabs