Skip to content

Alpine.js x-teleport Directive — Complete Guide with Examples

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you'll learn about the Alpine.js x-teleport directive. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

The Alpine.js x-teleport directive moves elements to a different part of the DOM while keeping the component's scope and reactivity intact, ideal for modals and overlays.

What You'll Learn

By the end of this tutorial, you'll teleport modals to the document body, teleport multiple elements to the same target, use teleport with x-if, and handle teleported component state.

Why It Matters

Modals, tooltips, dropdowns, and toast notifications need to break out of their parent container to avoid CSS overflow clipping and z-index issues. x-teleport moves them to the body while keeping their Alpine scope connected to the parent.

Real-World Use

Doda Browser uses x-teleport for its full-screen image viewer. The viewer element is teleported to the document body to cover the entire viewport, but its component state remains scoped to the gallery component that opened it.

Where This Fits in Your Learning Path

flowchart LR
    A["x-ref Directive"] --> B["**x-teleport Directive**"]
    B --> C["x-init & x-effect"]
    C --> D["Magics & Store"]
    D --> E["Advanced Alpine Patterns"]
    style B fill:#f97316,stroke:#c2410c,color:#fff
    style A fill:#e5e7eb,stroke:#9ca3af,color:#374151
    style E fill:#22c55e,stroke:#16a34a,color:#fff

What is x-teleport?

x-teleport moves an element (and all its children) to a CSS selector target in the DOM. The component's scope and reactivity stay with the original location.

Think of x-teleport like a wormhole. You enter at one location (the modal definition) and exit at another (the document body). Your component's state stays at the entry point, but the DOM element appears at the exit.

<div x-data="{ open: false }">
  <button @click="open = true">Open Modal</button>
  <template x-teleport="body">
    <div x-show="open" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">
      <div class="bg-white p-6 rounded-lg" @click.outside="open = false">
        <h2>Teleported Modal</h2>
        <p>This modal is teleported to the body element.</p>
        <button @click="open = false">Close</button>
      </div>
    </div>
  </template>
</div>

Expected output: The modal renders as a direct child of <body>, not nested inside the component's original DOM location.

Teleporting Multiple Elements

Multiple teleport templates can target the same selector. Content is appended in order.

<div x-data="{ toasts: [] }">
  <button @click="toasts.push(Date.now())" class="px-4 py-2 bg-blue-500 text-white rounded">Add Toast</button>
  <template x-for="id in toasts" :key="id">
    <template x-teleport="#toast-container">
      <div class="fixed top-4 right-4 bg-gray-800 text-white px-4 py-2 rounded shadow-lg">
        Toast <span x-text="id"></span>
      </div>
    </template>
  </template>
</div>
<div id="toast-container"></div>

Expected output: Each toast appears in the toast-container div at the bottom of the page, even though the component is at the top.

Teleport with x-if

Combine x-teleport with x-if to conditionally teleport content.

<div x-data="{ showPanel: false, user: { name: 'Alice', email: 'alice@example.com' } }">
  <button @click="showPanel = !showPanel">Toggle Panel</button>
  <template x-if="showPanel">
    <template x-teleport="body">
      <div class="fixed bottom-0 left-0 right-0 bg-white shadow-xl p-6 border-t">
        <h2 x-text="user.name"></h2>
        <p x-text="user.email"></p>
        <button @click="showPanel = false">Close</button>
      </div>
    </template>
  </template>
</div>

Expected output: The panel is teleported to the bottom of the body when shown, and completely removed from the DOM when hidden.

Common Mistakes

1. Using x-teleport without a valid selector

The target must be a valid CSS selector that exists in the DOM. If the target doesn't exist, teleport fails silently.

2. Teleporting to a target that appears after the component

If the target element is below the component in the DOM, it must exist when the teleport is evaluated. Place the target above or use a target that's always present.

3. Forgetting that teleported content is not scoped to the target

The teleported element's Alpine scope is still the original component, not the target location. Use $store or events to communicate with other components.

4. Using x-teleport inside x-for without keys

When teleporting inside x-for, ensure each item has a unique key so Alpine correctly tracks and moves individual elements.

5. Styling teleported elements assuming parent hierarchy

Since teleported elements move to a different DOM location, CSS rules that rely on parent selectors may break. Use fixed positioning or global classes instead.

Practice Questions

  1. What does x-teleport do? It moves the element to a different DOM location specified by a CSS selector while keeping the Alpine component scope intact.

  2. Why would you use x-teleport for modals? To break out of parent containers that might clip the modal with overflow: hidden or affect its z-index stacking.

  3. Does teleported content maintain its Alpine reactivity? Yes. The component's scope stays with the original location. State changes still update teleported content.

  4. Can you teleport to multiple targets? Each template targets one selector. Use multiple templates to teleport to different targets.

  5. What happens if the teleport target doesn't exist? Alpine will not teleport the content. Always ensure the target element exists in the DOM.

Challenge

Build a notification center with x-teleport. Each notification is teleported to a notification container at the body level. Include an auto-dismiss feature that removes notifications after 3 seconds.

FAQ

Can x-teleport target any CSS selector?

Yes. It accepts any valid CSS selector: element IDs (#target), classes (.container), or data attributes ([data-target]).

Does x-teleport work with Shadow DOM?

Standard Alpine x-teleport works with the main document DOM. For Shadow DOM, you need to use a custom target selector within the shadow root.

What is the performance impact of x-teleport?

Teleporting moves DOM nodes, which is a relatively expensive operation. For frequently toggled content, consider using fixed positioning instead.

Can I teleport form elements and keep their values?

Yes. Form elements within teleported content maintain their values and reactivity because the Alpine scope remains connected.

Does x-teleport preserve event listeners?

Yes. Event listeners on teleported elements are preserved because they are attached to the elements, not to the DOM position.


Mini Project

Build a toast notification system. A list of toasts is managed in the component. Each toast is teleported to a body-level container. Toasts auto-dismiss after 3 seconds and can be manually closed.

<div x-data="{ toasts: [], nextId: 1 }">
  <button @click="const id = nextId++; toasts.push(id); setTimeout(() => toasts = toasts.filter(t => t !== id), 3000)"
          class="px-4 py-2 bg-blue-500 text-white rounded">
    Show Toast
  </button>

  <template x-for="id in toasts" :key="id">
    <template x-teleport="body">
      <div class="fixed top-4 right-4 z-50 flex flex-col gap-2">
        <div class="bg-gray-800 text-white px-6 py-3 rounded-lg shadow-lg flex items-center gap-4">
          <span>Notification #<span x-text="id"></span></span>
          <button @click="toasts = toasts.filter(t => t !== id)" class="text-gray-400 hover:text-white">&times;</button>
        </div>
      </div>
    </template>
  </template>
</div>

What's Next

Further explore Alpine's initialization and effects:

Tutorial What You'll Learn
x-init Directive Run code when components initialize
x-effect Directive Run reactive side effects based on state

Related topics: CSS positioning and z-index, DOM manipulation.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro