HTML <portal>: Chrome's weird navigational element
Tags: webdev, dom, html, javascript
Published: 2022-06-17 15:21:55

## What's a Portal?
You might have never heard of the HTML `<portal>` element. It's an experimental feature since Chrome 75 (June, 2019) and its proposal is in the draft stages. But what is it exactly? Essentially the `<portal>` is like a souped-up `<iframe>` and includes the ability to seamlessly navigate into embedded content. 

Similar to an `<iframe>`, `<portal>` includes a `src` attribute which is the URL of the page you want to embed and the embedded content will look identical to an `<iframe>`. The `<portal>` is clickable but is not interactable since its purpose is to provide a smooth navigation into a prerended page - similar to the way most SPAs navigate. This differs from iframes which cannot immediately be navigated to without another request to the source. Clicking on a portal will navigate you right into all that content that's already loaded and rendered as the child inset of the parent document.

What's cool about portals is that they can be cross-origin, meaning you can create a portal to a different domain from where you're embedded it. 

## How To Use
So since portals are an experimental, we need to enable 2 flags in Chrome at `about://flags/#enable-portals`:

- 🚩 Enable Portals
- 🚩 Enable cross-origin Portals

Chrome will prompt you to relaunch your Browser and after doing so, you should see the `HTMLPortalElement` function available in your console:
<img width="400px" src="https://web-dev.imgix.net/image/admin/aUrrqhzMxaEX865Fk5zX.png?auto=format&w=1252">

So now let's create a basic portal! It's as easy as adding this HTML to your web page.
```html
<portal src="https://theoatmeal.com"></portal>
```

You can add styles to this element to adjust height, width, etc. but in its raw form you'll see the webpage from The Oatmeal embedded. When you click the portal, you navigate instantly to the source page and should not notice the normal "blink" you'd otherwise get from visiting a new Web page. 

## Let's Get Fancy
Here's a use case where we'll create a list of popular webcomics. Each block of content will show a preview image of the comic and when the user hovers over it our code will render a portal in place that can be clicked to navigate directly to the the webcomic's page:

<img src="https://github.com/doctafaustus/html-portal/blob/preview-gif/chrome_1sXGgQBBtJ.gif?raw=true">

First, the HTML:
```html
<h2>Best Webcomics</h2>
<ol>
  <li>
    <h3>The Oatmeal</h3>
    <div 
      class="comic-container"
      data-src="https://theoatmeal.com/comics/forbidden_love"
    >
      <img src="/forbidden_love_big.png">
      <img class="spinner" src="/spinner.gif">
      <portal src=""></portal>
    </div>
  </li>

  <!-- Repeat lis for other webcomics -->
</ol>
```

Notice we're using an empty `src` for the portal. To avoid unnecessary loading, we'll set the source in JavaScript only when the user hovers over `.comic-container` via the `mouseenter` event. As the source is being loaded, we'll show the spinner overlay so there's user feedback to show something is loading. Once fully loaded (by listening to the `load` event), we can display the portal over the existing image.

```js
const blocks = document.querySelectorAll('.comic-container');
blocks.forEach(block => {
  block.addEventListener('mouseenter', e => {
    block.classList.add('hover');
    const portal = block.querySelector('portal');
    const { src } = block.dataset;
    portal.src = src;
  });

  // Add "mouseleave" listener to reset classes
});

const portals = document.querySelectorAll('portal');
portals.forEach(portal => {
  portal.addEventListener('load', e => {
    if (portal.closest('.comic-container').matches('.hover')) {
      portal.classList.add('show-portal');
    } 
  });
});
```

From there, the user can click the portal and be instantly transported to the source page!

The default click behavior on a portal can also be prevented if you wanted to create a fancy animation the on click event and then call `portal.activate()` to activate the portal programmatically.

See full code here: [https://github.com/doctafaustus/html-portal](https://github.com/doctafaustus/html-portal)

## Closing Thoughts
While portals give us a new way to preview and prerender pages, it's unclear if they'll ever be standard in browsers. My first thoughts about security were assuaged by reading that portals do not allow user interaction to channel through to the "portaled" document. Additionally, the embedded content will not have direct access to the host document. However, portals would still introduce yet another opportunity to create clever browser exploits, so a sound content security policy (CSP) would be recommended.

Nevertheless, they're still pretty cool!
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qp3516kt8kpz9yj4vq9q.jpg)

----------
<b>Yo!</b> I post byte-sized tips like these often. Follow me if you crave more! 🍿

I'm on [Twitter](https://twitter.com/JS_Bits_Bill), [TikTok](https://www.tiktok.com/@js_bits) and I have a new [debugging course](https://www.udemy.com/course/js-bits-bug-bash/) out now!