HTMLPortalElement is a draft of a new HTML Element, very similar to iframes but with the big difference that it allows to navigate to the content of the "iframe" by using a page transition.
To know more about it, I recommend to read these references:
- https://wicg.github.io/portals/#the-portalactivateevent-interface
- https://web.dev/hands-on-portals
- https://github.com/WICG/portals/blob/master/explainer.md
In this article, I will explain how to use this future feature to do a "Hello world" demo with React.
Getting started
First of all, to use this draft feature you'll need Chrome Canary. Once you have it, activate the flag of Portals:
Next, we'll test portals. Remember that portals need to be on the top level of our app (unlike it happens with iframes).
Hello world with HTMLPortalElement and React:
import React, { useState, useEffect, useRef } from 'react'
import { render } from 'react-dom'
function PortalExample() {
if (!window.HTMLPortalElement) {
return 'HTMLPortalElement is not supported in your browser.'
}
return <portal src="https://aralroca.com" />
}
render(<PortalExample />, document.getElementById('root'))
We get a similar result than using an iframe:
Nevertheless, we want a beautiful transition to navigate to the content of this page. How could we get this?
Navigating to a portal
As I said, there is a significant difference between portals and iframes; with portals we can navigate to the content. In order to do that, the element has the function activate to go to the page.<portal
src="https://aralroca.com"
// navigate to content
onClick={({ target }) => target.activate()}
/>
Now we can navigate to the content. Although without any transition... yet:
Adding a page transition
Instead of calling the activate function on the onClick event, we are going to use the onClick event to add an extra css class with the transition. Then, we are going to use the onTransitionEnd event to control when the css transition is finished. After that, we'll call the activate function.Therefore, our css transition is going to scale the portal until the portal fits all the content of the page (width and height 100%).
React code:
import React, { useState } from 'react'
import { render } from 'react-dom'
import './style.css'
function PortalExample() {
const [transition, setTransition] = useState(false)
if (!window.HTMLPortalElement) {
return 'HTMLPortalElement is not supported in your browser.'
}
return (
<portal
src="https://aralroca.com"
className={`portal ${transition ? 'portal-reveal' : ''}`}
onClick={() => setTransition(true)}
onTransitionEnd={(e) =>
e.propertyName === 'transform' && e.target.activate()
}
/>
)
}
render(<PortalExample />, document.getElementById('root'))
Styles:
body {
background-color: #212121;
}
.portal {
position: fixed;
width: 100%;
cursor: pointer;
height: 100%;
transition: transform 0.4s;
box-shadow: 0 0 20px 10px #999;
transform: scale(0.4);
}
.portal.portal-reveal {
transform: scale(1);
}
Finally, we get the page transition in our portal:
Code: https://github.com/aralroca/HTMLPortalElement-react-example
Benefits of portals
Portals are a new proposal to load pages as an iframe, allowing the navigation to the content with a beautiful transition and improving the user's experience.They can be useful for previews of videos / audio, so you can navigate to the content page without stop watching / listening the media at any moment.
Of course, here we are using a different origin (YouTube). Nevertheless, if we use the same origin, we can communicate with the portal at any moment and do things like displaying a beauty preview or loading the rest of the content after the portal is activated.