Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Навіщо компонент Teleport і як правильно робити модальні вікна у Vue?

Модальне вікно логічно належить компоненту, що його відкриває (кнопка, стан, обробники - поруч). Але візуально воно має бути поверх усієї сторінки. Якщо розмітка вікна лишається глибоко в DOM усередині батьків, CSS батьків ламає позиціонування:

  • transform, filter, perspective на предку роблять position: fixed відносним до цього предка, а не до вікна;
  • overflow: hidden обрізає вікно;
  • z-index обмежений контекстом накладання (stacking context) батька.

<Teleport> рендерить вміст в інше місце DOM, лишаючи його логічно частиною компонента:

<script setup>
const open = ref(false);
</script>

<template>
  <button @click="open = true">Видалити акаунт</button>

  <Teleport to="body">
    <div v-if="open" class="fixed inset-0 z-50 grid place-items-center bg-black/50">
      <div role="dialog" aria-modal="true" class="rounded bg-white p-6">
        <p>Ви впевнені?</p>
        <button @click="open = false">Скасувати</button>
      </div>
    </div>
  </Teleport>
</template>

Що зберігається: реактивність, props, події, provide/inject - вміст лишається дочірнім у дереві компонентів. Змінюється лише місце в DOM.

Параметри:

  • to - CSS-селектор чи елемент; ціль має існувати на момент монтування;
  • :disabled="isMobile" - рендерити на місці (наприклад, на мобільних вікно стає звичайним блоком);
  • defer (Vue 3.5+) - відкласти пошук цілі до кінця поточного монтування, щоб ціллю міг бути елемент, який Vue рендерить пізніше в тому самому дереві.

Кілька Teleport в одну ціль дописують вміст по черзі - зручно для стеку сповіщень.

Що ще треба для якісного модального вікна (Teleport цього не робить):

  • фокус: перевести фокус у вікно при відкритті, втримувати його всередині (focus trap) і повертати на кнопку після закриття;
  • закриття по Escape і кліку на підкладку;
  • блокування прокрутки сторінки під вікном;
  • role="dialog", aria-modal, aria-labelledby для зчитувачів екрана.

Нативна альтернатива - елемент <dialog> з showModal(): браузер сам дає верхній шар (top layer, без проблем із z-index), фокус і Escape. У сучасних застосунках це часто простіше за Teleport.

SSR: телепортований вміст рендериться окремо - його треба вставити в HTML вручну, інакше буде розбіжність при гідратації.

Докладніше в документації: Teleport

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання