Open UIOpen UI

Popup (Editor's Draft)

Editors:

  • Mason Freed (Google)
  • Melanie Richards (Microsoft)

HTML Incubation Text: Popup

Target venue: HTML Living Standard

Categories:
Flow content.
Sectioning root.
Contexts in which this element can be used:
Where flow content is expected.
Content model:
Flow content.
Content attributes:
Global attributes
anchor — Creates an id-reference relationship with another element, which is used for both anchor positioning and popup stack management
delegatesfocus — Whether to move focus to the popup's first focusable element when the popup is shown
initiallyopen — Whether the popup is shown upon document load
Accessibility considerations:
Pending specification in ARIA in HTML and HTML-AAM.

Add IDL to frontmatter (#356)

A popup element represents transient application UI that “pops up” in the top layer of a web document, enabling the user to perform some task in a timely and immediate fashion. popup is similar to the dialog element, but is distinguished by its transient nature (“light dismiss” behaviors) and mutual exclusivity: only one popup element may be rendered at a time, with the exception of nested popups.

Examples of popups include: button menus, listboxes used for item selection e.g. comboboxes, "teaching" UI, and other progressive-disclosure widgets or content pickers.

The open IDL attribute, on getting, must return the last value to which it was set. On setting, it must be set to the new value. When the element is created, it must be set to false.

Showing a popup element

A popup element and its contents must not be rendered unless:

  • The initiallyopen attribute is specified
  • The show() method is invoked
  • Or the popup element has been invoked through user interaction with an element whose popup attribute references the popup element's ID

This requirement may be implemented indirectly through the style layer. For example, user agents that support the suggested default rendering implement this requirement using the CSS rules described in the Rendering section.

This specification introduces a new stacking layer in the document top layer, called the popup stack. Each document has one popup stack.

The popup stack is an ordered set of elements, rendered in the order they appear in the set. The last element in the set is rendered last, and thus appears on top.

Showing or hiding a popup element adds or removes the element from the popup stack, respectively.

The initiallyopen attribute

The initiallyopen attribute is a boolean attribute. When specified, it indicates that the popup element will be shown upon document load, such that the user can interact with it.

Example:

<popup initiallyopen></popup>

When a popup element becomes browsing-context connected, the user agent must run the following steps, given a popup element candidate subject:

  1. If the initiallyopen content attribute is specified on the candidate subject, run the showing a popup element steps.
  2. Otherwise, set the candidate subject's open state to false.

As a result of following this run step: in the event that initiallyopen is specified on multiple popups, the last of these popups (with the initiallyopen attribute) in the DOM order will be the popup that is rendered upon document load.

The show() method

The show() method renders the popup element, such that the user can interact with it.

Example:

<popup id="newFeatureUI">
<p>
<strong>New!</strong>
I’m some sort of educational UI…
</p>
</popup>
<script>
if (upsellNewFeature) {
document.getElementById('newFeatureUI').show()
}
</script>

The show() method steps are to run the showing a popup element steps with this.

The popup attribute

The popup attribute indicates that a related popup element will be shown or hidden as the user interacts with the element where the popup attribute is specified. If the attribute is specified, the attribute's value must be the ID of a popup element in the same node document.

Example: Invoking the button element in this example will show/hide the popup element, depending on whether or not the popup element is currently shown:

<button id="menuButton" popup="menuPopup">Menu</button>
<popup id="menuPopup" role="menu" anchor="menuButton">
<!-- Markup for menuitems goes here -->
</popup>

The popup attribute is supported on a subset of interactive elements:

  • button
  • input in the button state
  • input in the email, number, search, tel, text, or url states

Showing/hiding a popup element via the popup attribute

When an element with the popup attribute specified receives a user interaction that shows the related popup element, this element shall be known as the popup element's invoker.

Multiple elements may have a popup attribute that refers to the same popup element. A given popup element only has 0 or 1 invokers at a given time. For example, if the popup element was shown programmatically, the invoker is null. Otherwise, the element that the user actually interacted with to show the popup is its sole invoker.

If the invoker is a button element or an input element in the button state, and the invoker is activated; OR the invoker is an input in the email, number, search, tel, text, or url states and focus is set to the invoker, the user agent must run the following steps:

  1. Let subject be the first element in tree order with the ID referenced by the popup attribute specified on the invoker. If there is no such element, or the subject is not a popup element, then return.
  2. Get the subject's open state.
  3. If subject's open state is true, run hiding a popup element steps, with subject and invoker.
  4. Otherwise, run showing a popup element steps with subject and invoker.

Showing a popup element steps

The showing a popup element steps, given a popup element candidate subject and an optional element invoker, and an optional element anchor element, are:

  1. Run the hiding currently-shown popup elements steps, with the candidate subject, invoker if it was given, and anchor element if it was given.
  2. Add the candidate subject to candidate subject's node document's popup stack.
  3. Set the candidate subject's open state to true.
  4. If the popup element was shown as a result of a user interaction with an invoker, set the candidate subject's invoker to invoker.
  5. Let focusableArea be the result of getting the focusable area steps given candidate subject.
  6. Run the focusing steps given focusableArea.

Without the presence of the autofocus or delegatefocus attribute, focus remains on the active element. This behavior is to enable scenarios where the popup is used in a composite control. For example, a combobox where the user expects their focus to stay in the text input instead of moving automatically to the listbox popup as and when it appears.

Setting initial focus with the autofocus attribute

The autofocus content attribute allows the author to indicate that an element is to be focused as soon as the page is loaded or as soon as the popup within which it finds itself is shown.

When specified on the popup element, it indicates that when the popup element is shown, focus moves to the popup element.

Example:

<popup autofocus>
<p>The popup itself will receive focus.</p>
<button>A focusable element</p>
</popup>

When specified on a descendent of the popup element, it indicates that when the popup element is shown, focus will move to the descendent of the popup element where autofocus is specified.

Example:

<popup>
<p>Text goes here</p>
<button>Button one</button>
<button autofocus>Button two</p>
</popup>

Setting initial focus with the delegatesfocus attribute

The delegatesfocus content attribute is a boolean attribute. When specified, it indicates that when the popup element is shown, focus will move to the first focusable descendent of the popup element.

Example:

<popup delegatesfocus>
<p>I am not a focusable element.</p>
<p>Nor am I.</p>
<button>I will be focused whenever the popup becomes focused.</button>
</popup>

As currently written in thetext to be inserted into the "get the focusable area steps": if both the delegatesfocus and autofocus content attributes are set on the popup element, the delegatesfocus behavior will take precedence (will be used).

Anchoring a popup to another element

Many popups have a visual-logical relationship with another element that may not be a part of the popup element's ancestry chain. For example, a button may control a popup element, and the popup needs to be positioned with respect to this button. Or the popup element may simply be used to draw attention to or describe another element. The anchor attribute indicates this relationship. When specified, the attribute's value must be the ID of an element in the same node document as the popup element.

Example:

<button id="myButton">Anchor element</button>
<popup open anchor="myButton">
<p>
<strong>New!</strong>
I’m some sort of educational UI…
</p>
</popup>

The target of the anchor attribute participates in determining whether a candidate popup element is "nested" in a currently-shown popup; refer to hiding currently-shown popup elements steps.

Whenever there is a spec to point to for CSS anchored positioning, call out here that the anchor attribute is used to help resolve CSS anchor() functions.

Hiding a popup element

The hide() method

The hide() method hides a popup element. The hide() method steps are to run the hiding a popup element steps with this.

Light dismissal

"Light dismiss" describes the behavior of a component which dismisses itself automatically when a user performs an action that implies that they are finished interacting with the component. The actions that trigger light dismiss are:

  • The user presses the escape key.
  • A focus change occurs (because of either user interaction or script), where the focus target is outside of the contents of the component. This includes the case where the user invokes a non-focusable element, which causes focus to jump to the nearest focusable ancestor of that element.
  • An OS-level focus change occurs such that the window containing the component no longer has focus. For example, the user switches to a different browser tab or switches to a different application.

When a popup element is shown and a light dismiss interaction occurs:

  1. If a keypress event for the ESCAPE key was fired, run hiding a popup element steps, with the candidate subject set to the top-most popup element in the popup stack.
  2. If a focus change occurs, the user agent must set the start node to the element which received the focus event and run Hiding currently-shown popup elements steps.
  3. Otherwise, the user agent must set the start node to null and run Hiding currently-shown popup elements steps.

Hiding currently-shown popup elements steps

The hiding currently-shown popup elements steps, given an optional popup element candidate subject, an optional element invoker, and an optional element anchor element, and an optional element start node, are as follows.

For each popup element subject in the node document's popup stack:

  1. If candidate subject is null, run the hiding a popup element steps, with subject as candidate subject.
  2. Otherwise, starting with the candidate subject, walk the flat tree to determine whether the subject is an ancestor to the candidate subject. If this condition is met, then return.
  3. Otherwise, if the invoker is not null, starting with the invoker, walk the flat tree to determine whether the subject is an ancestor to the invoker. If this condition is met, then return.
  4. Otherwise, if the anchor element is not null, starting with the anchor element, walk the flat tree to determine whether the subject is an ancestor to the anchor element. If this condition is met, then return.
  5. If start node is not null:
  6. If the start node is the subject, then return.
  7. Otherwise, starting with the start node, walk the flat tree to determine whether the subject is an ancestor to the start node. If this condition is met, then return.
  8. Otherwise, for this subject, run the hiding a popup element steps, with subject as candidate subject, and optional element invoker.

Hiding a popup element steps

The hiding a popup element steps, given a popup element candidate subject and an optional element invoker, are as follows:

  1. Remove the candidate subject from the node document's popup stack.
  2. Set the candidate subject's open state to false.
  3. Set the candidate subject's invoker to null.
  4. Queue an element task on the user interaction task source given the candidate subject element to fire an event named hide at candidate subject.

HTML Incubation Text: User Interaction > Focus > Processing Model

The following text to be inserted into theget the focusable area steps.

If focus target is a popup element

  1. If the delegatesfocus attribute is specified on focus target, return the first focusable descendent element of focus target, in tree order, that is not inert.
  2. If there is no such descendent, but delegatesfocus is specified, return the focus target.
  3. Otherwise, if the autofocus attribute is specified on focus target, return the focus target.
  4. Otherwise, if the autofocus attribute is specified on a descendent element of focus target, return the first such descendent element of focus target, in tree order, that is not inert.
  5. Otherwise, return.