In NOVA LAB the alarm system displays an alert on the station's main screen, regardless of which module triggered it. Vue has
<Teleport> - a mechanism for rendering content in a different place in the DOM, outside the component hierarchy.Modals, toasts, and popups logically belong to a component, but visually they should be rendered at the top level of the DOM (e.g., directly in
<body>) to avoid issues with z-index, overflow: hidden, and positioning.1<script setup>
2import { ref } from 'vue'
3const showModal = ref(false)
4</script>
5
6<template>
7 <div class="module-panel">
8 <h2>Oxygen Module</h2>
9 <button @click="showModal = true">Show Alert</button>
10
11 <Teleport to="body">
12 <div v-if="showModal" class="modal-overlay">
13 <div class="modal">
14 <h3>Critical Alert!</h3>
15 <p>Oxygen level below 20%</p>
16 <button @click="showModal = false">Dismiss</button>
17 </div>
18 </div>
19 </Teleport>
20 </div>
21</template>The content inside
<Teleport> is physically rendered in <body>, but logically belongs to the component - it has access to its data and props.The
to attribute accepts a CSS selector:1<!-- To body -->
2<Teleport to="body">...</Teleport>
3
4<!-- To an element with an ID -->
5<Teleport to="#modal-container">...</Teleport>
6
7<!-- To an element with a class -->
8<Teleport to=".notifications">...</Teleport>You can dynamically disable teleportation:
1<script setup>
2import { ref } from 'vue'
3const isMobile = ref(false)
4</script>
5
6<template>
7 <!-- On mobile render locally, on desktop in body -->
8 <Teleport to="body" :disabled="isMobile">
9 <div class="popup">
10 <p>Popup content</p>
11 </div>
12 </Teleport>
13</template>When
disabled=true, the content renders in its original place in the component tree.You can have multiple
<Teleport> elements rendering to the same element - content is appended in order:1<template>
2 <Teleport to="#notifications">
3 <div class="toast">Alert 1</div>
4 </Teleport>
5
6 <Teleport to="#notifications">
7 <div class="toast">Alert 2</div>
8 </Teleport>
9</template>