Portal
`pura-portal` is a headless teleporter (no appearance of its own, `display: contents`) that physically moves the child nodes into a mount element appended to the target, escaping clipping (overflow), transform, filter, or the z-index stacking context of some ancestor. Use it when an overlay or menu needs to render outside the parent container's clip without losing the logical link to its origin. It exposes a machine-readable layer: stable data-* attributes on the host (data-portal-id, data-to, data-active), a mount element marked with data-pura-portal-mount and data-portal-owner, and a global registry `window.__puraPortals` (a Map with query() and forTarget() helpers) so that agents can trace the teleported content back to its logical owner.
Preview
<div style="position:relative;overflow:hidden;height:120px;border:1px solid #d4d4d8;border-radius:8px;padding:16px;background:#fafafa">
<p style="margin:0 0 8px">Container with <code>overflow:hidden</code> (clips the content).</p>
<pura-portal id="demo-portal" to="body">
<div style="position:fixed;bottom:24px;right:24px;padding:12px 16px;background:#18181b;color:#fff;border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.25)">
Teleported to the <strong><body></strong>, escaping the clip.
</div>
</pura-portal>
</div>
<button id="demo-toggle" type="button" style="margin-top:12px;padding:8px 14px;border:1px solid #d4d4d8;border-radius:6px;cursor:pointer">Toggle teleport</button>
<script type="module">
const portal = document.getElementById("demo-portal");
document.getElementById("demo-toggle").addEventListener("click", () => {
portal.toggleAttribute("disabled");
});
portal.addEventListener("pura-portal:mount", (e) => console.log("mount", e.detail));
portal.addEventListener("pura-portal:unmount", (e) => console.log("unmount", e.detail));
</script> Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
to | string | body | Teleport destination. The keyword "body" (default) points to document.body; any other value is treated as a CSS selector resolved via document.querySelector. If it matches nothing, the content stays in place (graceful degradation). |
disabled | boolean | false | When present, the portal does NOT teleport: the content stays inline in its original position. |
Installation
pura is copy-paste and dependency-free. Load the whole library, or just this component.
<link rel="stylesheet" href="/pura/tokens.css">
<script type="module" src="/pura/lib/portal.js"></script> import "./pura/lib/portal.js";