Skip to main content
Vuetify0 is now in beta!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

Portal

Renderless teleport wrapper with automatic z-index stacking.

Usage

Portal wraps Vue’s <Teleport> with automatic useStack integration. Content is teleported to body by default and receives a zIndex via slot props for proper overlay ordering.

Mobile — renders inline below
<script setup lang="ts">
  import { Portal, useBreakpoints } from '@vuetify/v0'
  import { shallowRef } from 'vue'

  const show = shallowRef(false)
  const { smAndDown: mobile } = useBreakpoints()
</script>

<template>
  <div class="flex flex-col gap-4">
    <div class="flex items-center gap-4">
      <button
        class="rounded bg-primary px-4 py-2 text-on-primary"
        @click="show = true"
      >
        Show overlay
      </button>

      <span class="text-sm text-on-surface-variant">
        {{ mobile ? 'Mobile — renders inline below' : 'Desktop — teleported to body' }}
      </span>
    </div>

    <Portal v-if="show" :disabled="mobile" @close="show = false">
      <template #default="{ zIndex, close }">
        <div
          class="rounded-lg bg-surface-variant p-4 shadow-lg"
          :class="mobile ? '' : 'fixed bottom-4 right-4'"
          :style="mobile ? {} : { zIndex }"
        >
          <div class="flex items-start justify-between gap-4">
            <div>
              <p class="text-sm font-medium">Portal Content</p>

              <p class="mt-1 text-xs text-on-surface-variant">
                z-index: {{ zIndex }} · {{ mobile ? 'inline' : 'teleported' }}
              </p>
            </div>

            <button
              class="rounded px-2 py-1 text-xs text-on-surface-variant hover:bg-surface hover:text-on-surface"
              @click="close"
            >
              close
            </button>
          </div>
        </div>
      </template>
    </Portal>
  </div>
</template>

Anatomy

vue
<script setup lang="ts">
  import { Portal } from '@vuetify/v0'
</script>

<template>
  <Portal />
</template>

Accessibility

Portal is transparent — it adds no DOM elements, ARIA attributes, or keyboard behavior. Accessibility is the responsibility of the content you teleport.

Tip

When teleporting interactive content (modals, menus, notifications), ensure it has proper ARIA roles, keyboard handling, and focus management. Portal handles where content renders, not how it behaves.

FAQ

Discord
Need help? Join our community for support and discussions ↗

API Reference

The following API details are for all variations of the Portal component.
Was this page helpful?

Ctrl+/