1. Introduction
This section is non-normative.
This specification extends [HTML] to define a new kind of top-level browsing context , which can be embedded in another document, and a mechanism for replacing the contents of another top-level browsing context with the previously embedded context.
It is structured as a series of patches to HTML and other specifications, with each major section indicating where each it would be placed in the event of eventual graduation from incubation.
2. Portal browsing contexts
The following section would be added as a new sub-section of [HTML] 's Browsing contexts section.
Every
browsing
context
has
a
portal
state
,
which
may
be
"
none
"
(the
default),
"
portal
"
or
"
orphaned
".
A
nested
browsing
context
always
has
the
portal
state
"
none
".
-
"
portal": top-level browsing contexts embedded in aportalelement -
"
orphaned": top-level browsing contexts which have runactivatebut have not (yet) been adopted -
"
none": all other browsing contexts
A
top-level
"
none
"
context
can
become
"
orphaned
"
by
activating
another
context.
An
"
orphaned
"
context
can
be
adopted
to
become
a
"
portal
"
context.
A
"
portal
"
context
can
become
a
"
none
"
context
by
being
activated
by
its
host
browsing
context
.
A browsing context can be closed while in any of these states.
A
portal
browsing
context
is
a
browsing
context
whose
portal
state
is
"
portal
".
The
host
element
of
a
portal
browsing
context
is
a
portal
element
which
embeds
its
rendered
output
and
receives
messages
sent
from
the
portal
browsing
context.
portal
element
may
only
be
a
host
element
while
it
is
browsing-context
connected
or
during
the
dispatch
of
the
portalactivate
event
from
which
it
was
obtained
using
adoptPredecessor()
.
The host browsing context of a portal browsing context is its host element 's document 's browsing context .
The portal task source is a task source used for tasks related to the portal lifecycle and communication between a portal browsing context and its host browsing context .
-
Assert : The portal state of predecessorBrowsingContext is "
none". -
Set the host element of successorBrowsingContext to null.
User agents should , however, attempt to preserve the rendering of the guest browsing context until predecessorBrowsingContext has been replaced with successorBrowsingContext in the rendering.
Note: This is intended to avoid a visual glitch, such as a "white flash", where the guest browsing context briefly disappears.
-
Set the portal state of predecessorBrowsingContext to "
orphaned". -
Update the user interface to replace predecessorBrowsingContext with successorBrowsingContext (e.g., by updating the tab/window contents and browser chrome).
-
Let successorWindow be successorBrowsingContext ’s associated
WindowProxy's [[Window]] internal slot value. -
Queue a task from the portal task source to the event loop associated with successorWindow to run the following steps:
-
Assert : The portal state of successorBrowsingContext is "
portal". -
Set the portal state of successorBrowsingContext to "
none". -
Let targetRealm be successorWindow ’s realm .
-
Let deserializeRecord be StructuredDeserializeWithTransfer ( serializeWithTransferResult , targetRealm ), and let dataClone be deserializeRecord .[[Deserialized]].
If this throws an exception, catch it, and let dataClone be null instead.
-
Let event be the result of creating an event using
PortalActivateEventand targetRealm . -
Initialize event ’s
typeattribute toportalactivate. -
Initialize event ’s
dataattribute to dataClone . -
Initialize event ’s
originattribute to origin . Set event ’s predecessor browsing context to predecessorBrowsingContext .
-
Set event ’s successor window to successorWindow .
-
Set event ’s activation promise to promise .
-
Dispatch event to successorWindow .
-
Let adoptedPredecessorElement be event ’s adopted predecessor element .
-
If adoptedPredecessorElement is not null, then:
-
Set adoptedPredecessorElement ’s just-adopted flag to false.
-
If adoptedPredecessorElement may not have a guest browsing context and its guest browsing context is not null, then discard it.
This unceremoniously discards the browsing context, as if the element had been removed from the document after previously being attached. This is distinct from the case where the predecessor was never adopted, below, which closes the browsing context, which dispatches theunloadevent, somewhat similarly to if it had performed an ordinary navigation.Typically authors would not call
adoptPredecessor()unless they intend to insert it into the document before the just-adopted flag becomes false.
-
-
Otherwise:
-
Queue a task from the portal task source to the event loop associated with predecessorBrowsingContext to resolve promise with undefined.
-
Close predecessorBrowsingContext .
The user agent should not ask the user for confirmation during the prompt to unload step (and so the browsing context should be discarded ).
-
-
- portal-activate-event.html (live test) (source)
- portals-host-hidden-after-activation.html (live test) (source)
-
Let document be the document of successorWindow .
-
Let portalElement be the result of creating an element given document ,
portal, and the HTML namespace . -
Set portalElement ’s just-adopted flag to true.
-
Assert : portalElement is an
HTMLPortalElement. -
Queue a task from the portal task source to the event loop associated with predecessorBrowsingContext to run the following steps:
-
Assert : The portal state of predecessorBrowsingContext is "
orphaned". -
Set the portal state of predecessorBrowsingContext to "
portal", and set the host element of predecessorBrowsingContext to portalElement .
-
-
Return portalElement .
PortalHost
object,
is
queued
first,
and
from
the
same
task
source
,
it
is
exposed
at
the
time
the
activation
promise
returned
from
activate(options)
is
resolved.
// In the successor document. onportalactivate= event=> { // The predecessor document is adopted into a <portal> element... document. body. appendChild( event. adoptPredecessor()); }); // In the predecessor document. portalElement. activate(). then(() => { // ...and it is guaranteed to observe that change by the time the // activation promise resolves. console. assert( window. portalHostinstanceof PortalHost); });
3.
The
portal
element
The following section would be added as a new subsection of [HTML] 's Embedded content section.
A
portal
element
allows
for
a
portal
browsing
context
to
be
embedded
in
an
HTML
document.
A
portal
element
portalElement
has
a
guest
browsing
context
,
which
is
the
portal
browsing
context
whose
host
element
is
portalElement
,
or
null
if
no
such
browsing
context
exists.
A
portal
element
has
a
just-adopted
flag
,
which
is
a
boolean
and
is
initially
false.
It
is
set
during
dispatch
of
the
portalactivate
event.
The
src
attribute
gives
the
URL
of
a
page
that
the
guest
browsing
context
is
to
contain.
The
attribute,
if
present,
must
be
a
valid
non-empty
URL
potentially
surrounded
by
spaces
.
The
referrerpolicy
attribute
is
a
referrer
policy
attribute
.
Its
purpose
is
to
set
the
referrer
policy
used
when
setting
the
source
URL
of
a
portal
element
.
[REFERRER-POLICY]
A
portal
is
similar
to
an
iframe
,
in
that
it
allows
another
browsing
context
to
be
embedded.
However,
the
portal
browsing
context
hosted
by
a
portal
is
part
of
a
separate
browsing
context
group
,
and
thus
a
separate
agent
.
The
user
agent
is
therefore
free
to
use
a
separate
event
loop
for
the
browsing
contexts,
even
if
they
are
same
origin-domain
.
[Exposed =Window ,HTMLConstructor ]interface :HTMLPortalElement HTMLElement { [CEReactions ]attribute USVString src ; [CEReactions ]attribute DOMString referrerPolicy ; [NewObject ]Promise <void >activate (optional PortalActivateOptions );options void postMessage (any ,message USVString ,targetOrigin optional sequence <object >= []);transfer void postMessage (any ,message optional WindowPostMessageOptions );options attribute EventHandler ;onmessage attribute EventHandler ; };onmessageerror dictionary {PortalActivateOptions any =data null ;sequence <object >= []; };transfer
The
src
IDL
attribute
must
reflect
the
src
content
attribute.
The
referrerPolicy
IDL
attribute
must
reflect
the
referrerpolicy
content
attribute,
limited
to
only
known
values
.
activate(
options
)
method
must
run
these
steps:
-
Let portalBrowsingContext be the guest browsing context of this .
-
If portalBrowsingContext is null, throw an "
InvalidStateError"DOMException. -
Let predecessorBrowsingContext be the browsing context of this 's document .
-
If predecessorBrowsingContext is null, throw an "
InvalidStateError"DOMException. -
If the portal state of predecessorBrowsingContext is not "
none", throw an "InvalidStateError"DOMException.Note: This means that a
portalelement inside a portal browsing context cannot be activated. -
Let serializeWithTransferResult be StructuredSerializeWithTransfer ( options ["
data"], options ["transfer"]). Rethrow any exceptions. -
Let origin be the serialization of this 's relevant settings object 's origin .
Let promise be a new promise .
-
Run the steps toactivateActivate portalBrowsingContext in place of predecessorBrowsingContext withdataserializeWithTransferResult , origin , andpromisepromise . -
Return promise .
postMessage(
message
,
targetOrigin
,
transfer
)
method
must
run
these
steps:
-
Let options be « "
targetOrigin" → targetOrigin , "transfer" → transfer ». -
Run the steps for
postMessage( message , options ).
The
postMessage(
message
,
options
)
method
must
run
these
steps:
-
Let portalBrowsingContext be the guest browsing context of this .
-
If portalBrowsingContext is null, throw an "
InvalidStateError"DOMException. -
Let settings be the relevant settings object of this .
-
Let origin be the serialization of settings ’s origin .
-
Let targetOrigin be options ["
targetOrigin"]. -
If targetOrigin is a single U+002F SOLIDUS character (/), then set targetOrigin to the origin of settings .
-
Otherwise, if targetOrigin is not a single U+002A ASTERISK character (*), then:
-
Let parsedURL be the result of running the URL parser on targetOrigin .
-
If parsedURL is failure, then throw a "
SyntaxError"DOMException. -
Set targetOrigin to parsedURL ’s origin .
-
-
Let transfer be options ["
transfer"]. -
Let serializeWithTransferResult be StructuredSerializeWithTransfer ( message , transfer ). Rethrow any exceptions.
-
Queue a task from the portal task source to the event loop of portalBrowsingContext to run the following steps:
-
If targetOrigin is not a single literal U+002A ASTERISK character (*) and the origin of portalBrowsingContext ’s active document is not same origin with targetOrigin , then abort these steps.
-
Let targetWindow be portalBrowsingContext ’s associated
WindowProxy's [[Window]] internal slot value. -
Let portalHost be the targetWindow ’s portal host object .
-
Let targetRealm be the targetWindow ’s realm .
-
Let deserializeRecord be StructuredDeserializeWithTransfer ( serializeWithTransferResult , targetRealm ).
If this throws an exception, catch it, fire an event named
messageerrorat portalHost usingMessageEventwith theoriginattribute initialized to origin and thesourceattribute initialized to portalHost , then abort these steps. -
Let messageClone be deserializeRecord .[[Deserialized]].
-
Let newPorts be a new frozen array consisting of all
MessagePortobjects in deserializeRecord .[[TransferredValues]], if any, maintaining their relative order. -
Fire an event named
messageat portalHost usingMessageEvent, with theoriginattribute initialized to origin , thesourceattribute initialized to portalHost , thedataattribute initialized to messageClone , and theportsattribute initialized to newPorts .
-
portal
element
may
have
a
guest
browsing
context
,
run
the
following
steps:
-
If element ’s document 's browsing context is not a top-level browsing context , then return false.
The user agent may choose to emit a warning if the author attempts to use a
portalelement in a nested browsing context , as this is not supported. -
If element ’s document 's URL 's scheme is not an HTTP(S) scheme , then return false.
This is to prevent problems later, if the portaled content attempts to adopt its predecessor . Since portaled content can only have a HTTP(S) scheme , adoption would fail, and so its simpler to restrict things at this stage.
-
If element is browsing-context connected , then return true.
-
If element ’s just-adopted flag is true, then return true.
-
Return false.
portal
element
element
,
run
the
following
steps:
-
If element ’s guest browsing context is not null, then close it.
The user agent should not ask the user for confirmation during the prompt to unload step (and so the browsing context should be discarded ).
portal
element
element
,
run
the
following
steps:
-
Assert : element may have a guest browsing context .
-
Let hostBrowsingContext be element ’s document 's browsing context .
-
Assert : hostBrowsingContext is a top-level browsing context .
-
If element has no
srcattribute specified, or its value is the empty string, then close element and return. -
Parse the value of the
srcattribute. If that is not successful, then close element and return.Otherwise, let url be the resulting URL record .
-
If the scheme of url is not an HTTP(S) scheme , then close element and return.
-
If element ’s guest browsing context is null, then run the following steps:
-
Let newBrowsingContext be the result of creating a new top-level browsing context .
-
Set the portal state of newBrowsingContext to "
portal", and set the host element of newBrowsingContext to element .
-
-
Let guestBrowsingContext be element ’s guest browsing context .
-
Assert : guestBrowsingContext is not null.
-
Let resource be a new request whose URL is url and whose referrer policy is the current state of element ’s
referrerpolicycontent attribute. -
Navigate guestBrowsingContext to resource .
iframe
element,
a
portal
element
supports
a
state
where
it
has
no
associated
browsing
context.
This
is
the
initial
state
of
a
portal
element
(i.e.,
it
has
no
initial
about:blank
document;
instead
it
navigates
directly
to
the
first
parsable
URL
assigned
to
it).
Similarly,
a
portal
element
responds
to
an
unparsable
src
URL
by
closing
its
browsing
context,
rather
than
by
navigating
to
about:blank
.
- portal-non-http-navigation.html (live test) (source)
- portals-cross-origin-load.sub.html (live test) (source)
- portals-referrer.html (live test) (source)
- portals-referrer-inherit-header.html (live test) (source)
- portals-referrer-inherit-meta.html (live test) (source)
Whenever
a
portal
element
element
has
its
src
attribute
set,
changed,
or
removed,
run
the
following
steps:
-
If element may have a guest browsing context , then set the source URL of element .
Whenever
a
portal
element
element
becomes
browsing-context
connected
,
run
the
following
steps:
-
If element may not have a guest browsing context , then abort these steps.
-
If element ’s guest browsing context is not null, then abort these steps.
-
Set the source URL of element .
Whenever
a
portal
element
element
becomes
browsing-context
disconnected
,
run
the
following
steps:
-
If element may not have a guest browsing context and its guest browsing context is not null, then discard it.
portal
element
without
losing
its
browsing
context.
Whenever
a
portal
element
element
is
adopted
,
run
the
following
steps:
-
Let guestBrowsingContext be element ’s guest browsing context .
-
If guestBrowsingContext is null, then abort these steps.
-
Discard guestBrowsingContext .
portal
element
loses
its
guest
browsing
context
if
it
is
moved
to
the
active
document
of
a
nested
browsing
context
.
Similarly,
the
steps
when
a
portal
element’s
source
URL
is
set
prevent
elements
from
creating
a
new
guest
browsing
context
while
inside
such
documents.
It is therefore impossible to embed a portal browsing context in a nested browsing context .
The
following
events
are
dispatched
on
HTMLPortalElement
objects:
| Event name | Interface | Dispatched when |
|---|---|---|
message
|
MessageEvent
| A message is received by the object, and deserialization does not throw an exception. |
messageerror
|
MessageEvent
| A message is received by the object, but deserialization throws an exception. |
The
portal
element
exposes
onmessage
and
onmessageerror
as
event
handler
content
attributes
.
3.1. Portal hosts
Every
Window
has
a
portal
host
object
,
which
is
a
PortalHost
.
It
is
exposed
through
the
portalHost
attribute
getter
at
times
when
the
window
may
be
in
a
portal
browsing
context
.
window.portalHost
getter
will
return
null.
partial interface Window {readonly attribute PortalHost ?portalHost ; };
portalHost
attribute’s
getter
must
run
the
following
steps:
-
Let context be this 's browsing context .
-
If context is null or the portal state of context is not "
portal", then return null. -
Return this 's portal host object .
The
PortalHost
interface
definition
is
as
follows:
[Exposed =Window ]interface :PortalHost EventTarget {void postMessage (any ,message USVString ,targetOrigin optional sequence <object >= []);transfer void postMessage (any ,message optional WindowPostMessageOptions );options attribute EventHandler ;onmessage attribute EventHandler ; };onmessageerror
postMessage(
message
,
targetOrigin
,
transfer
)
method
must
run
these
steps:
-
Let options be « "
targetOrigin" → targetOrigin , "transfer" → transfer ». -
Run the steps for
postMessage( message , options ).
The
postMessage(
message
,
options
)
method
must
run
these
steps:
-
Let settings be the relevant settings object of this .
-
Let browsingContext be the responsible browsing context of settings .
-
If browsingContext has a portal state other than "
portal", throw an "InvalidStateError"DOMException.Note: This roughly means that it has not yet been activated, as far as this event loop has been told. It is possible that this browsing context will be activated in parallel to this message being sent; in such cases, messages may not be delivered.
-
Let origin be the serialization of settings ’s origin .
-
Let targetOrigin be options ["
targetOrigin"]. -
If targetOrigin is a single U+002F SOLIDUS character (/), then set targetOrigin to the origin of settings .
-
Otherwise, if targetOrigin is not a single U+002A ASTERISK character (*), then:
-
Let parsedURL be the result of running the URL parser on targetOrigin .
-
If parsedURL is failure, then throw a "
SyntaxError"DOMException. -
Set targetOrigin to parsedURL ’s origin .
-
-
Let transfer be options ["
transfer"]. -
Let serializeWithTransferResult be StructuredSerializeWithTransfer ( message , transfer ). Rethrow any exceptions.
-
Let hostElement be the host element of browsingContext .
-
Let hostBrowsingContext be the host browsing context of browsingContext .
-
Queue a task from the portal task source to the event loop associated with hostBrowsingContext to run the following steps:
-
If browsingContext is not the guest browsing context of hostElement , then abort these steps.
Note: This might happen if this event loop had a queued task to deliver a message, but it was not executed before the portal was activated . In such cases, the message is not delivered.
-
Let targetSettings be the relevant settings object of hostElement .
-
If targetOrigin is not a single literal U+002A ASTERISK character (*) and targetSettings ’s origin is not same origin with targetOrigin , then abort these steps.
-
Let targetRealm be targetSettings ’s realm .
-
Let deserializeRecord be StructuredDeserializeWithTransfer ( serializeWithTransferResult , targetRealm ).
If this throws an exception, catch it, fire an event named
messageerrorat element usingMessageEventwith theoriginattribute initialized to origin and thesourceattribute initialized to element . -
Let messageClone be deserializeRecord .[[Deserialized]].
-
Let newPorts be a new frozen array consisting of all
MessagePortobjects in deserializeRecord .[[TransferredValues]], if any, maintaining their relative order. -
Fire an event named
messageat the element usingMessageEvent, with theoriginattribute initialized to origin , thesourceattribute initialized to element , thedataattribute initialized to messageClone , and theportsattribute initialized to newPorts .
-
The
following
events
are
dispatched
on
PortalHost
objects:
| Event name | Interface | Dispatched when |
|---|---|---|
message
|
MessageEvent
| A message is received by the object, and deserialization does not throw an exception. |
messageerror
|
MessageEvent
| A message is received by the object, but deserialization throws an exception. |
3.2.
The
PortalActivateEvent
interface
[Exposed =Window ]interface :PortalActivateEvent Event {(constructor DOMString ,type optional PortalActivateEventInit = {});eventInitDict readonly attribute any ;data readonly attribute USVString ;origin HTMLPortalElement adoptPredecessor (); };dictionary :PortalActivateEventInit EventInit {any =data null ; };
A
PortalActivateEvent
has
an
associated
predecessor
browsing
context
,
which
is
a
top-level
browsing
context
or
null,
a
successor
window
,
which
is
a
Window
,
an
activation
promise
,
which
is
a
promise
,
and
a
adopted
predecessor
element
,
which
is
a
portal
element
or
null.
PortalActivateEvent
,
given
an
event
,
are
as
follows:
-
Set event ’s predecessor browsing context to null.
-
Set event ’s successor window to null.
-
Set event ’s adopted predecessor element to null.
adoptPredecessor()
method
must
run
these
steps:
-
If this 's adopted predecessor element is not null, throw an "
InvalidStateError"DOMException. -
Let predecessorBrowsingContext be this 's predecessor browsing context .
-
Let successorWindow be this 's successor window .
-
Run the steps to adopt the predecessor browsing context predecessorBrowsingContext in successorWindow , and let adoptedPredecessorElement be the result.
-
Set this 's adopted predecessor element to adoptedPredecessorElement .
-
Queue a task from the portal task source to the event loop associated with predecessorBrowsingContext to resolve this 's activation promise with undefined.
Note: Queuing this immediately makes it possible to send messages to the adopted portal during dispatch of the
portalactivateevent without ordering issues between the task to resolve the activation promise and the task to deliver the message. -
Return adoptedPredecessorElement .
4. Miscellaneous HTML updates
This section contains various small patches to miscellaneous areas of the HTML Standard.
4.1.
The
MessageEvent
interface
The
MessageEventSource
union
is
extended
to
include
the
new
interfaces
which
can
produce
MessageEvent
events.
typedef (WindowProxy or MessagePort or ServiceWorker or HTMLPortalElement or PortalHost );MessageEventSource
4.2. Event handlers
The
table
of
event
handlers
which
must
be
supported
by
Window
objects,
as
event
handler
IDL
attributes
on
the
Window
objects
themselves
(i.e.
the
table
containing
onafterprint
),
gets
extended
with
the
following
row:
| Event handler | Event handler event type |
|---|---|
onportalactivate
|
portalactivate
|
The
corresponding
WindowEventHandlers
mixin
gets
extended
as
follows:
partial interface mixin WindowEventHandlers {attribute EventHandler ; };onportalactivate
The Events index is also updated with the following additional row:
| Event | Interface | Interesting targets | Description |
|---|---|---|---|
portalactivate
|
PortalActivateEvent
|
Window
|
Fired
at
the
Window
of
a
portal
browsing
context
when
that
portal
browsing
context
is
activated.
|
5. Updates to other specifications
5.1. Content Security Policy
This specification integrates with [CSP] as follows.
-
If request ’s initiator is "", its destination is "
document", and its target browsing context is a portal browsing context , returnframe-src.
-
Replace all references to " nested browsing context " with " nested browsing context or portal browsing context ".
-
Replace all references to " parent browsing context " with " parent browsing context or host browsing context ".
5.2. RFC 7034
This
specification
integrates
with
[RFC7034]
,
which
defines
the
X-Frame-Options
HTTP
header,
as
follows.
Note
that
[HTML]
also
has
an
open
issue,
whatwg/html#1230
,
to
define
X-Frame-Options
processing,
and
perhaps
these
updates
would
be
done
as
part
of
resolving
that
issue.
If a browser receives content with this header field in response to a navigation request whose target browsing context is a portal browsing context , then the browser must apply the rules in [RFC7034] as though it were to be displayed in a frame in the host browsing context instead and as though the origin of the top-level browsing context topLevelBrowsingContext were the origin of the result of the following algorithm:
-
While topLevelBrowsingContext is a portal browsing context :
-
Set topLevelBrowsingContext to its host browsing context .
-
-
Return topLevelBrowsingContext .
5.3. Fetch Metadata Request Headers
This specification integrates with [FETCH-METADATA] as follows.
-
Where the algorithm checks whether r ’s reserved client 's target browsing context is a nested browsing context , check instead whether it is a nested browsing context or a portal browsing context .
Sec-Fetch-Mode: nested-navigate
iframe
element,
with
no
spec
updates
needed.
6. Security Considerations
6.1. Overview
This section is non-normative.
In general, a portal browsing context should respect policies that would apply to a nested browsing context , e.g. that would restrict whether a document can be embedded in a document from another origin .