An excerpt from the repository, fetched Nov 13, 2026.
Read the project’s introduction
The Portals proposal is not currently being actively pursued.
Many of the capabilities that Portals would have enabled are being explored in other proposals:
navigation speculation (including speculation rules, prefetch, and prerendering)
View Transitions
Fenced Frame
and more (which may be added here)
This repository is thus effectively archived for the time being.
Portals
Portals enable seamless and instant navigations between pages. In particular, we propose a new <portal> HTML element which enables a page to show another page as an inset, and then activate it to perform a seamless transition to a new state, where the formerly-inset page becomes the top-level document.
Portals are part of a general effort toward privacy-conscious, well-specified prerendering. They go beyond basic prerendering support by also providing the inset preview of the content. This makes them suitable for seamless navigations, not just instant ones; for example, they enable web-developer-controlled navigation transitions between the referring page and the prerendered page. Their inset form also can serve as a more-private and more-secure form of an iframe, in certain cases.
Table of contents
Examples
Introductory example
Navigation transitions
Use cases
Objectives
Details
Same-origin communication channels
Rendering
Interactivity
Accessibility
Session history, navigation, and bfcache
Activation
CSP integration
Embedder-imposed policies and delegation
Summary of differences between portals and iframes
Alternatives considered
A new attribute on an existing element
TODO:
Security and privacy considerations
Stakeholder feedback
Acknowledgments
Examples
Introductory example
A document can include a <portal> element, which prerenders the specified URL in the portal:
<portal id="myPortal" src="https://example.com/"></portal>
This prerenders https://example.com/ in a prerendering browsing context, which imposes certain restrictions such as no use of permission-requiring APIs, or no access to storage in the cross-origin case. Importantly, cross-origin content will need to opt in to such prerendering.
But unlike other prerendering technologies, where the prerendering takes place entirely offscreen, the portal element shows a preview of the prerendered content. In this way it is somewhat like an iframe, providing a rendered view of another page. Note, however, that a portal's preview is much more restricted than the general embedding mechanism iframes provide; e.g., user interaction with does not pass through to the portaled content.
When the portaled content is same-origin, the embedding page can communicate with it using
myPortal.postMessage(data);
This can be useful to coordinate the preview displayed. However, when the portaled content is cross-origin, postMessage() does not function, so as to prevent cross-site tracking.
While all prerendered content can be activated, becoming fully-rendered top-level content, portals expose this ability to web developers directly. That is, while other prerendering technologies rely on the browser to implicitly activate the prerendered content, with portals the web developer can call
myPortal.activate();
which causes the embedding window to navigate, replacing its document with the prerendered one. At this point, the user will observe that their browser has navigated to https://example.com/, e.g., via changes to the URL bar contents and back/forward UI. Since https://example.com/ was already loaded and prerendered in the portal context, this navigation will occur seamlessly and instantly, without a network round-trip or document re-initialization.
For more advanced use cases, the https://example.com/ document can react to activation, using the portalactivate event. It can use this event to adapt itself to its new context. For example, if the page was only showing preview content while in a portal, it can switch to showing the full content of the page. The page can also adopt its predecessor (the document which previously occupied the tab) into a new portal context.
window.addEventListener('portalactivate', e => {
document.body.classList.add('displayed-fully');
document.requestStorageAccess().then(() => {
document.getElementById('user').textContent = localStorage.getItem('current-user');
});
let predecessor = e.adoptPredecessor(document);
console.assert(predecessor instanceof HTMLPortalElement);
document.body.appendChild(predecessor);
});
If https://example.com/ does not need to adapt portal-specific content when activated and does not need the predecessor-adoption capability, then it can instead use the generic APIs for reacting to prerendering activation or other relevant changes, outlined in that explainer.
Navigation transitions
As a more realistic example, consider a page which wants to prerender a link and provide a seamless navigation transition when it's clicked. It can do this by hiding the portal until the link is clicked,
and then animating the portal to full screen before activation.
This might be written like so:
<a href="https://example.com/" class="seamless">Click me!</a>
<script>
for (const link of document.querySelectorAll('a.seamless')) {
const portal = document.createElement('portal');
portal.src = link.href;
portal.hidden = true;
portal.style = 'position: fixed; top: 0; left: 0; width: 10vw; height: 10vh;';
document.body.append(portal);
link.onclick = async e => {
if (portal.state === 'empty') {
// The content couldn't be portaled, likely because it didn't opt-in.
// Let the normal link click go through.
return;
}
e.preventDefault();
// Show the portal, and animate it to the whole viewport over 300 milliseconds.
if (!matchMedia('(prefers-reduced-motion: reduce)').matches) {
portal.hidden = false;
await portal.animate([{ width: '100vw', height: '100vh' }], { duration: 300 }).finished;
}
// Once the preview is now displayed as the whole viewport, activate.
Read the full README on GitHub