Portal
UtilitiesLocal guide ↗
import { Portal } from "bits-ui" Named target
Move the same child between its declaration site and a specific DOM target
Invocation site
source treeNo child here in the DOM
Named target
#portal-demo-targetThe child moves without changing where the Portal is declared.
<script lang="ts">
import { Portal } from 'bits-ui';
let inline = $state(false);
</script>
<div class="grid gap-4 sm:grid-cols-2">
<section class="panel min-h-36 p-4">
<div class="mb-3 flex items-center justify-between gap-2">
<p class="text-xs font-semibold tracking-wider text-ink-200 uppercase">Invocation site</p>
<code class="chip">source tree</code>
</div>
<div class="grid min-h-20 place-items-center rounded-lg border border-dashed border-ink-700 p-3">
<Portal to="#portal-demo-target" disabled={inline}>
<div class="panel animate-pop-in border-brand-500/50 px-4 py-3 text-center text-sm">
<p class="font-medium text-brand-400">Portal child</p>
<p class="muted mt-1 text-xs">Currently rendered {inline ? 'inline' : 'in #portal-demo-target'}</p>
</div>
</Portal>
{#if !inline}<p class="muted text-center text-xs">No child here in the DOM</p>{/if}
</div>
</section>
<section class="panel min-h-36 p-4">
<div class="mb-3 flex items-center justify-between gap-2">
<p class="text-xs font-semibold tracking-wider text-ink-200 uppercase">Named target</p>
<code class="chip">#portal-demo-target</code>
</div>
<div id="portal-demo-target" class="grid min-h-20 place-items-center rounded-lg border border-dashed border-brand-500/40 p-3">
{#if inline}<p class="muted text-center text-xs">Target is empty</p>{/if}
</div>
</section>
</div>
<div class="mt-4 flex flex-wrap items-center gap-3">
<button class="btn btn-primary btn-sm" onclick={() => (inline = !inline)}>
{inline ? 'Enable portal' : 'Disable portal'}
</button>
<p class="muted text-xs">The child moves without changing where the Portal is declared.</p>
</div>
Without a to prop, Portal appends its children to document.body. The target may instead be an Element or selector string; a named target is useful when an overlay must stay inside a particular stacking or theme boundary.
Set disabled to render at the original DOM location. The same Portal implementation backs the Portal sub-component exposed by Bits UI overlays, and BitsConfig can replace its default target for an entire subtree.