Portals

Draft Community Group Report,

This version:
https://wicg.github.io/portals/
Issue Tracking:
GitHub
Inline In Spec
Editors:
(Google)
(Google)

Abstract

This specification defines a mechanism that allows for rendering of, and seamless navigation to, embedded content.

Status of this document

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

This spec is behind the explainer

This specification document has not yet been updated to reflect the 2020-04 updates to the explainer. We’ll fix that as soon as we can, but please be aware that there are probably contradictions, and the explainer should be taken as more authoritative for the time being.

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".

Briefly, these correspond to:
  • "portal": top-level browsing contexts embedded in a portal element

  • "orphaned": top-level browsing contexts which have run activate but have not (yet) been adopted

  • "none": all other browsing contexts

Diagram of portal state transitions

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.

A 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 node 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.

To activate a portal browsing context successorBrowsingContext in place of predecessorBrowsingContext with origin sourceOrigin, optional data serializeWithTransferResult, and optional promise promise, run the following steps in parallel:
  1. Assert: The portal state of predecessorBrowsingContext is "none".

  2. 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.

  3. Set the portal state of predecessorBrowsingContext to "orphaned".

  4. Update the user interface to replace predecessorBrowsingContext with successorBrowsingContext (e.g., by updating the tab/window contents and browser chrome).

  5. Let successorWindow be successorBrowsingContext’s associated WindowProxy's [[Window]] internal slot value.

  6. Queue a global task on the portal task source given successorWindow to run the following steps:

    1. Assert: The portal state of successorBrowsingContext is "portal".

    2. Set the portal state of successorBrowsingContext to "none".

    3. Let targetRealm be successorWindow’s realm.

    4. Let dataClone be null.

    5. If serializeWithTransferResult is given and successorBrowsingContext’s active document's origin is same origin with sourceOrigin, then:

      1. Let deserializeRecord be StructuredDeserializeWithTransfer(serializeWithTransferResult, targetRealm), and set dataClone to deserializeRecord.[[Deserialized]].

        If this throws an exception, catch it and do nothing.

    6. Let event be the result of creating an event using PortalActivateEvent and targetRealm.

    7. Initialize event’s type attribute to portalactivate.

    8. Initialize event’s data attribute to dataClone.

    9. Set event’s predecessor browsing context to predecessorBrowsingContext.

    10. Set event’s successor window to successorWindow.

    11. Set event’s activation promise to promise, if it is given, and null otherwise.

    12. Dispatch event to successorWindow.

    13. Let adoptedPredecessorElement be event’s adopted predecessor element.

    14. If adoptedPredecessorElement is not null, then:

      1. Set adoptedPredecessorElement’s just-adopted flag to false.

      2. 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 the unload event, 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.

    15. Otherwise:

      1. If promise is given, queue a global task on the portal task source given predecessorBrowsingContext’s active window to resolve promise with undefined.

      2. 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).

In the case that structured deserialization throws, it may be useful to do something else to indicate it, rather than simply providing null data.
We need to specify how the session history of each browsing context is affected by activation, and supply non-normative text that explains how these histories are expected to be presented to the user.
To adopt the predecessor browsing context predecessorBrowsingContext in successorWindow, run the following steps:
  1. Let document be the document of successorWindow.

  2. Let portalElement be the result of creating an element given document, portal, and the HTML namespace.

  3. Set portalElement’s just-adopted flag to true.

  4. Assert: portalElement is an HTMLPortalElement.

  5. Queue a global task on the portal task source given predecessorBrowsingContext’s active window to run the following steps:

    1. Assert: The portal state of predecessorBrowsingContext is "orphaned".

    2. Set the portal state of predecessorBrowsingContext to "portal", and set the host element of predecessorBrowsingContext to portalElement.

  6. Return portalElement.

Since the task to set the portal state, and thus expose the 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.portalHost instanceof 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, optional PostMessageOptions options = {});

    attribute EventHandler onmessage;
    attribute EventHandler onmessageerror;
};

dictionary PortalActivateOptions : PostMessageOptions {
    any data;
};

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.

The activate(options) method must run these steps:
  1. Let portalBrowsingContext be the guest browsing context of this.

  2. If portalBrowsingContext is null, throw an "InvalidStateError" DOMException.

  3. Let predecessorBrowsingContext be the browsing context of this's node document.

  4. If predecessorBrowsingContext is null, throw an "InvalidStateError" DOMException.

  5. If the portal state of predecessorBrowsingContext is not "none", throw an "InvalidStateError" DOMException.

    Note: This means that a portal element inside a portal browsing context cannot be activated.

  6. Let serializeWithTransferResult be StructuredSerializeWithTransfer(options["data"], options["transfer"]). Rethrow any exceptions.

  7. Let promise be a new promise.

  8. Let sourceOrigin be this's relevant settings object's origin.

  9. Run the steps to activate portalBrowsingContext in place of predecessorBrowsingContext with sourceOrigin, serializeWithTransferResult, and promise.

  10. Return promise.

The postMessage(message, options) method must run these steps:
  1. Let portalBrowsingContext be the guest browsing context of this.

  2. If portalBrowsingContext is null, throw an "InvalidStateError" DOMException.

  3. Let sourceOrigin be this's relevant settings object's origin.

  4. Let transfer be options["transfer"].

  5. Let serializeWithTransferResult be StructuredSerializeWithTransfer(message, transfer). Rethrow any exceptions.

  6. Queue a global task on the portal task source given portalBrowsingContext’s active window to run the following steps:

    1. If portalBrowsingContext’s active document's origin is not same origin with sourceOrigin, then abort these steps.

    2. Let origin be the serialization of sourceOrigin.

    3. Let targetWindow be portalBrowsingContext’s associated WindowProxy's [[Window]] internal slot value.

    4. Let portalHost be the targetWindow’s portal host object.

    5. Let targetRealm be the targetWindow’s realm.

    6. Let deserializeRecord be StructuredDeserializeWithTransfer(serializeWithTransferResult, targetRealm).

      If this throws an exception, catch it, fire an event named messageerror at portalHost using MessageEvent with the origin attribute initialized to origin and the source attribute initialized to portalHost, then abort these steps.

    7. Let messageClone be deserializeRecord.[[Deserialized]].

    8. Let newPorts be a new frozen array consisting of all MessagePort objects in deserializeRecord.[[TransferredValues]], if any, maintaining their relative order.

    9. Fire an event named message at portalHost using MessageEvent, with the origin attribute initialized to origin, the source attribute initialized to portalHost, the data attribute initialized to messageClone, and the ports attribute initialized to newPorts.

To determine whether a portal element may have a guest browsing context, run the following steps:
  1. If element’s node 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 portal element in a nested browsing context, as this is not supported.

  2. If element’s node 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.

  3. If element’s node document's active sandboxing flag set is not empty, then return false.

    Since portals cannot be created in child browsing contexts anyway, this step is about preventing portal uses in auxiliary browsing contexts spawned by sandboxed iframes, or pages using CSP’s sandbox directive.

    This restriction is largely added for simplicity. If there are use cases for portals inside sandboxed documents, we can enable them in the future, with appropriate opt-in. See issue #207 for discussion.

  4. If element is browsing-context connected, then return true.

  5. If element’s just-adopted flag is true, then return true.

  6. Return false.

To close a portal element element, run the following steps:
  1. 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).

To set the source URL of a portal element element, run the following steps:
  1. Assert: element may have a guest browsing context.

  2. Let hostBrowsingContext be element’s node document's browsing context.

  3. Assert: hostBrowsingContext is a top-level browsing context.

  4. If element has no src attribute specified, or its value is the empty string, then close element and return.

  5. Parse the value of the src attribute. If that is not successful, then close element and return.

    Otherwise, let url be the resulting URL record.

  6. If the scheme of url is not an HTTP(S) scheme, then close element and return.

  7. If element’s guest browsing context is null, then run the following steps:

    1. Let newBrowsingContext be the result of creating a new top-level browsing context.

    2. Set the portal state of newBrowsingContext to "portal", and set the host element of newBrowsingContext to element.

  8. Let guestBrowsingContext be element’s guest browsing context.

  9. Assert: guestBrowsingContext is not null.

  10. Let resource be a new request whose URL is url and whose referrer policy is the current state of element’s referrerpolicy content attribute.

  11. Navigate guestBrowsingContext to resource.

Unlike an 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.

Whenever a portal element element has its src attribute set, changed, or removed, run the following steps:

  1. 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:

  1. If element may not have a guest browsing context, then abort these steps.

  2. If element’s guest browsing context is not null, then abort these steps.

    This ensures that a newly adopted portal element can be inserted into the document without navigating it.
  3. Set the source URL of element.

Whenever a portal element element becomes browsing-context disconnected, run the following steps:

  1. If element may not have a guest browsing context and its guest browsing context is not null, then discard it.

It might be convenient to not immediately detach the portal element, but instead to do so in a microtask. This would allow developers to reinsert the portal element without losing its browsing context.

Whenever a portal element element is adopted, run the following steps:

  1. Let guestBrowsingContext be element’s guest browsing context.

  2. If guestBrowsingContext is null, then abort these steps.

  3. Discard guestBrowsingContext.

In particular, this means a 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.

Whenever a Document object document whose browsing context is a portal browsing context is marked as completely loaded, run the following steps as part of the queued task:

  1. Let element be document’s browsing context's host element.

  2. Fire an event named load at element.

A portal element el’s activation behavior is to run the following steps:
  1. Let portalBrowsingContext be the guest browsing context of el.

  2. If portalBrowsingContext is null, return.

  3. Let predecessorBrowsingContext be the browsing context of el’s node document.

  4. If predecessorBrowsingContext is null, return.

  5. If the portal state of predecessorBrowsingContext is not "none", return.

  6. Let sourceOrigin be el’s relevant settings object's origin.

  7. Run the steps to activate portalBrowsingContext in place of predecessorBrowsingContext with sourceOrigin.

This is substantially similar to the steps in activate(options), with default options. User agents might wish to display suitable console messages under the same conditions that would result in promise rejection in those steps.

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.

The portal host object can be used to communicate with the host browsing context. Its operations throw if used while its context is not a portal browsing context (i.e. there is no host), in the event that JavaScript code has saved a reference to it. At such times, the window.portalHost getter will return null.
partial interface Window {
    readonly attribute PortalHost? portalHost;
};
The portalHost attribute’s getter must run the following steps:
  1. Let context be this's browsing context.

  2. If context is null or the portal state of context is not "portal", then return null.

  3. Return this's portal host object.


The PortalHost interface definition is as follows:

[Exposed=Window]
interface PortalHost : EventTarget {
    void postMessage(any message, optional PostMessageOptions options);

    attribute EventHandler onmessage;
    attribute EventHandler onmessageerror;
};
The postMessage(message, options) method must run these steps:
  1. Let browsingContext be this's relevant global object's browsing context.

  2. 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.

  3. Let sourceOrigin be this's relevant settings object's origin.

  4. Let transfer be options["transfer"].

  5. Let serializeWithTransferResult be StructuredSerializeWithTransfer(message, transfer). Rethrow any exceptions.

  6. Let hostElement be the host element of browsingContext.

  7. Queue an element task on the portal task source given hostElement to run the following steps:

    1. 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.

    2. Let targetSettings be the relevant settings object of hostElement.

    3. If targetSettings’s origin is not same origin with sourceOrigin, then abort these steps.

    4. Let origin be the serialization of sourceOrigin.

    5. Let targetRealm be targetSettings’s realm.

    6. Let deserializeRecord be StructuredDeserializeWithTransfer(serializeWithTransferResult, targetRealm).

      If this throws an exception, catch it, fire an event named messageerror at element using MessageEvent with the origin attribute initialized to origin and the source attribute initialized to element.

    7. Let messageClone be deserializeRecord.[[Deserialized]].

    8. Let newPorts be a new frozen array consisting of all MessagePort objects in deserializeRecord.[[TransferredValues]], if any, maintaining their relative order.

    9. Fire an event named message at the element using MessageEvent, with the origin attribute initialized to origin, the source attribute initialized to element, the data attribute initialized to messageClone, and the ports attribute 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;
    HTMLPortalElement adoptPredecessor();
};

dictionary PortalActivateEventInit : EventInit {
    any data = null;
};
For now, there is no ports attribute on PortalActivateEvent, despite it being used for data transfer in a similar way to MessageEvent. This omission is for simplicity, and could be reconsidered if a use case is found. (See also whatwg/html#4521 for a potential expansion.)

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 or null, and a adopted predecessor element, which is a portal element or null.

The event constructing steps for PortalActivateEvent, given an event, are as follows:
  1. Set event’s predecessor browsing context to null.

  2. Set event’s successor window to null.

  3. Set event’s adopted predecessor element to null.

The adoptPredecessor() method must run these steps:
  1. If this's adopted predecessor element is not null, throw an "InvalidStateError" DOMException.

  2. Let predecessorBrowsingContext be this's predecessor browsing context.

  3. Let successorWindow be this's successor window.

  4. Run the steps to adopt the predecessor browsing context predecessorBrowsingContext in successorWindow, and let adoptedPredecessorElement be the result.

  5. Set this's adopted predecessor element to adoptedPredecessorElement.

  6. If this's activation promise is not null, queue a global task on the portal task source given predecessorBrowsingContext’s active window to resolve it with undefined.

    Note: Queuing this immediately makes it possible to send messages to the adopted portal during dispatch of the portalactivate event without ordering issues between the task to resolve the activation promise and the task to deliver the message.

  7. 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.

The algorithm for determining the effective directive for a request request is modified by prepending the following:
  1. If request’s initiator is "", its destination is "document", and its target browsing context is a portal browsing context, return frame-src.

The frame-ancestors Navigation Response Check is modified as follows:
  1. Replace all references to "nested browsing context" with "nested browsing context or portal browsing context".

  2. Replace all references to "parent browsing context" with "parent browsing context or host browsing context".

activate(options) should also respect the CSP navigate-to directive.

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:

  1. While topLevelBrowsingContext is a portal browsing context:

    1. Set topLevelBrowsingContext to its host browsing context.

  2. Return topLevelBrowsingContext.

5.3. Fetch Metadata Request Headers

This specification integrates with [FETCH-METADATA] as follows.

The algorithm to set the Sec-Fetch-Mode header for a request r is modified as follows:
  1. 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.

The effect of this is that the request for a document in a portal browsing context will contain the following HTTP header, as though it were in a nested browsing context.
    Sec-Fetch-Mode: nested-navigate
Per the existing processing model, the other fetch metadata headers will automatically have the same values as they would would if the load were occurring in an iframe element, with no spec updates needed.

6. Security Considerations

We should expand this section further. Much of what was formerly there is in § 5 Updates to other specifications now. Once we have a more comprehensive view of all the security-related spec updates, we should summarize them in a non-normative fashion here.

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.

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSP]
Mike West. Content Security Policy Level 3. 15 October 2018. WD. URL: https://www.w3.org/TR/CSP3/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/
[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[REFERRER-POLICY]
Jochen Eisinger; Emily Stark. Referrer Policy. 26 January 2017. CR. URL: https://www.w3.org/TR/referrer-policy/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[SERVICE-WORKERS-1]
Alex Russell; et al. Service Workers 1. 19 November 2019. CR. URL: https://www.w3.org/TR/service-workers-1/
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WebIDL]
Boris Zbarsky. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

Informative References

[FETCH-METADATA]
Mike West. Fetch Metadata Request Headers. 10 January 2020. WD. URL: https://www.w3.org/TR/fetch-metadata/
[RFC7034]
D. Ross; T. Gondrom. HTTP Header Field X-Frame-Options. October 2013. Informational. URL: https://tools.ietf.org/html/rfc7034

IDL Index

[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, optional PostMessageOptions options = {});

    attribute EventHandler onmessage;
    attribute EventHandler onmessageerror;
};

dictionary PortalActivateOptions : PostMessageOptions {
    any data;
};

partial interface Window {
    readonly attribute PortalHost? portalHost;
};

[Exposed=Window]
interface PortalHost : EventTarget {
    void postMessage(any message, optional PostMessageOptions options);

    attribute EventHandler onmessage;
    attribute EventHandler onmessageerror;
};

[Exposed=Window]
interface PortalActivateEvent : Event {
    constructor(DOMString type, optional PortalActivateEventInit eventInitDict = {});

    readonly attribute any data;
    HTMLPortalElement adoptPredecessor();
};

dictionary PortalActivateEventInit : EventInit {
    any data = null;
};

typedef (WindowProxy or MessagePort or ServiceWorker or HTMLPortalElement or PortalHost) MessageEventSource;

partial interface mixin WindowEventHandlers {
    attribute EventHandler onportalactivate;
};

Issues Index

In the case that structured deserialization throws, it may be useful to do something else to indicate it, rather than simply providing null data.
We need to specify how the session history of each browsing context is affected by activation, and supply non-normative text that explains how these histories are expected to be presented to the user.
It might be convenient to not immediately detach the portal element, but instead to do so in a microtask. This would allow developers to reinsert the portal element without losing its browsing context.
activate(options) should also respect the CSP navigate-to directive.
We should expand this section further. Much of what was formerly there is in § 5 Updates to other specifications now. Once we have a more comprehensive view of all the security-related spec updates, we should summarize them in a non-normative fashion here.