1. 6.11 The popup attribute
      1. 6.11.1 The pop-up target attributes
      2. 6.11.2 Pop-up light dismiss
      3. 6.11.3 The defaultopen attribute
      4. 6.11.4 The anchor attribute

6.11 The popup attribute

All elements may have the popup content attribute set. When specified, the element won't be rendered until it becomes shown, at which point it will be rendered on top of other page content.

The popup attribute is an enumerated attribute. The following table lists the states for this attribute:

State Keywords Description
Auto state auto Closes other pop-ups when opened; has light dismiss.
The empty string
Hint state hint Closes other hint pop-ups when opened; has light dismiss.
Manual state manual Does not close other pop-ups; does not light dismiss.

The popUp IDL attribute must reflect the popup attribute.

The attribute may be omitted. The invalid value default and the missing value default are both the manual state.

When the popup attribute is not set on an element, then the element's popup attribute is considered to be in the no pop-up state.

Every element has a pop-up visibility state with these potential values:

The pop-up visibility transitioning state and :open pseudo selectors exist to allow pop-ups to animate open or closed because animating between display: none and other 'display' values is not possible.

The following is an example of an animated pop-up:

<div popup="auto" id="foo">
  A fancy pop-up with no Javascript
</div>
<style>
  [popup] {
    opacity: 0;
    transform: translate(-100px,100px);
    transition: all 1.5s;
  }
  [popup]:open {
    transform: translate(0,0);
    opacity: 1;
  }
</style>

The Document has an auto pop-up stack, which is a stack, initially empty.

The Document has a currently-showing hint pop-up, which is an Element or null, initially null.

The Document has pop-ups waiting to hide, which is a set, initially empty.

The Document has a pop-up mousedown target, which is an Element or null, initially null.

Every element has the following members:

The following attribute change steps are used for the popup attribute:

  1. If localName is not popup, then return.

  2. If oldValue is in the no pop-up state, then return.

  3. If value is not in the no pop-up state, then return.

  4. Run the hide pop-up algorithm given element, true, and false.

element.showPopUp()
Shows the pop-up element by adding it to the top layer. If element's popup attribute is in the auto state or hint state, then this will also close all other auto and hint pop-ups unless they are an ancestor of element according to the nearest open ancestral pop-up algorithm.
element.hidePopUp()
Hides the pop-up element by removing it from the top layer and applying display: none to it.

The showPopUp() method steps are:

  1. Run show pop-up given this.

To show pop-up, given an Element element:

  1. If element's popup attribute is in the no pop-up state, then throw a "NotSupportedError" DOMException.

  2. If element's pop-up visibility state is not hidden, then throw a "InvalidStateError" DOMException.

  3. If element is not connected, then throw a "InvalidStateError" DOMException.

  4. If the result of firing an event named popupshow at element is false, then return.

  5. If element is not connected, then return.

  6. If element's popup attribute is in the no pop-up state, then return.

  7. If element's pop-up visibility state is showing, then return.

    These validity checks are repeated because firing the popupshow event could have disconnected this element or changed its popup attribute.

  8. Let document be element's node document.

  9. Let shouldRestoreFocus be false.

  10. If element's popup attribute is in the hint state, then:

    1. If document's currently-showing hint pop-up is not null, then run the hide pop-up algorithm given document's currently-showing hint pop-up, true, and false.

    2. Let ancestor be the result of running the nearest open ancestral pop-up algorithm given element and "new-pop-up".

    3. If ancestor is not null, then run hide all pop-ups until given ancestor, false, false, and true.

  11. If element's popup attribute is in the auto state, then:

    1. Let ancestor be the result of running the nearest open ancestral pop-up algorithm given element and "new-pop-up".

    2. Run hide all pop-ups until given ancestor, false, false, and true.

  12. If element's popup attribute is in the auto state or in the hint state, then:

    1. If element's popup attribute is in the no pop-up state, then return.

    2. If element's pop-up visibility state is not hidden, then return.

    3. If element is not connected, then return.

      These validity checks are repeated because running hide all pop-ups until above could have fired the popuphide event, and an event handler could have disconnected this element or changed its popup attribute.

    4. If the result of running topmost pop-up auto or hint on document is null, then set shouldRestoreFocus to true. Otherwise, set shouldRestoreFocus to false.

      This ensures that focus is returned to the previously-focused element only for the first pop-up in a stack.

  13. If element's popup attribute is in the auto state, then push element onto document's auto pop-up stack.

  14. If element's popup attribute is in the hint state, then set document's currently-showing hint pop-up to element.

  15. Set element's waiting to hide pop-up to false.

  16. Set element's pop-up previously focused element to null.

  17. Let originallyFocusedElement be document's focused area of the document.

  18. Add element to document's top layer.

  19. Set element's pop-up visibility state to transitioning.

  20. Recalculate styles and update layout for document.

  21. Set element's pop-up visibility state to showing.

  22. Run the pop-up focusing steps given element.

  23. If shouldRestoreFocus is true, element's popup attribute is not in the no pop-up state, and originallyFocusedElement is not the focused element, then set element's pop-up previously focused element to originallyFocusedElement.

The hidePopUp() method steps are:

  1. If this's popup attribute is in the no pop-up state, then throw a "NotSupportedError" DOMException.

  2. If this's pop-up visibility state is not showing, then throw a "InvalidStateError" DOMException.

  3. Run the hide pop-up algorithm given this, true, and false.

To hide a pop-up given an Element element, a boolean focusPreviousElement, and a boolean hideImmediately:

  1. Let document be element's node document.

  2. If element's popup attribute is in the auto state or the hint state, then:

    1. Run hide all pop-ups until given element, focusPreviousElement, hideImmediately, and false.

    2. If element's popup attribute is in the no pop-up state, then return.

    3. If element is not connected, then return.

    4. If element's pop-up visibility state is not showing, then return.

      These validity checks are repeated because running hide all pop-ups until above could have fired the popuphide event, and an event handler could have disconnected this element or changed its popup attribute.

    5. If element's popup attribute is in the auto state, then pop from document's auto pop-up stack.

    6. If element's popup attribute is in the hint state, then set document's currently-showing hint pop-up to null.

  3. Add element to document's pop-ups waiting to hide.

  4. Let previousAnimations be the set of all relevant Animation objects that contain at least one animation effect whose effect target is element.

  5. Set element's pop-up invoker to null.

  6. Set element's pop-up visibility state to transitioning.

  7. If hideImmediately is true, then:

    1. Queue an element task given user interaction task source and element to fire an event named popuphide at element.

    2. Run pop-up hide finish if needed given element.

    3. Return.

  8. Fire an event named popuphide at element.

  9. If element is not connected, then return.

  10. If element's popup attribute is in the no pop-up state, then return.

  11. If element's pop-up visibility state is transitioning, then return.

  12. Let animations be the set of all relevant Animation objects that contain at least one animation effect whose effect target is element.

  13. Remove all items in animations which exist in previousAnimations.

  14. If animations is empty, then run pop-up hide finish if needed given element.

  15. Let previouslyFocusedElement be element's previously focused element.

  16. If previouslyFocusedElement is not null, then:

    1. Set element's previously focused element to null.

    2. If focusPreviousElement is true, then run the focusing steps for previouslyFocusedElement.

  17. If animations is not empty, then run these steps in parallel:

    1. Set element's waiting to hide pop-up to true.

    2. Wait for each animation in animations to resolve as either canceled or finished.

    3. If element's waiting to hide pop-up is true, then run pop-up hide finish if needed given element.

To finish hiding a pop-up if needed, given an Element element:

  1. Remove element from element's node document's pop-ups waiting to hide.

  2. Remove element from the top layer.

  3. Set element's pop-up visibility state to hidden.

  4. Set element's waiting to hide pop-up to false.

To hide all pop-ups until, given an Element endpoint, a boolean focusPreviousElement, a boolean hideImmediately, and a boolean hideUnrelated:

  1. Let document be endpoint's node document.

  2. If hideImmediately is true, then:

    1. For each elementWaitingToHide in document's pop-ups waiting to hide:

      1. Run pop-up hide finish if needed given elementWaitingToHide.

    2. Clear document's pop-ups waiting to hide.

  3. If endpoint's popup attribute is in the hint state and hideUnrelated is true, then:

    1. If document's currently-showing hint pop-up is not equal to endpoint, then run the hide pop-up algorithm given endpoint, focusPreviousElement, and hideImmediately.

    2. While document's auto pop-up stack is not empty:

      1. Run the hide pop-up algorithm given endpoint, focusPreviousElement, and hideImmediately.

  4. If endpoint's popup attribute is in the auto state or endpoint is null, then:

    1. Let hintAncestor be null.

    2. If document's currently-showing hint pop-up is not null, then:

      1. Let hintAncestor be the result of running the nearest open ancestral pop-up algorithm given document's currently-showing hint pop-up and "default"

      2. If hintAncestor is null and hideUnrelated is true, then run the hide pop-up algorithm given document's currently-showing hint pop-up, focusPreviousElement and hideImmediately.

    3. While document's auto pop-up stack is not empty:

      1. If document's auto pop-up stack's top element is hintAncestor, then run the hide pop-up algorithm given document's currently-showing hint pop-up, focusPreviousElement and hideImmediately.

      2. If document's auto pop-up stack's top element is equal to endpoint, then break.

      3. Run the hide pop-up algorithm given document's auto pop-up stack's top element, focusPreviousElement, and hideImmediately.

The hide all pop-ups until algorithm is used in several cases to hide all pop-ups that don't stay open when something happens. For example, during light-dismiss of a pop-up, this algorithm ensures that we close only the pop-ups that aren't related to the node clicked by the user. The interaction between popup=auto and popup=hint is captured here, where a popup=hint that is "nested" inside a popup=auto is only hidden at the appropriate time.

To find the nearest open ancestral pop-up, given a Node node and a string ancestorType, perform the following steps. They return an Element or null.

  1. Let document be node's node document.

  2. Let hintShowing be document's currently-showing hint pop-up.

  3. Let anchorsToPopUps be an empty map.

  4. For each popUp in document's auto pop-up stack:

    1. Let anchor be the result of getting the pop-up anchor element of popUp.

    2. If anchor is not null, then set anchorsToPopUps[anchor] to popUp.

  5. If hintShowing is not null, then:

    1. Let anchor be the result of running getting the pop-up anchor element of hintShowing.

    2. If anchor is not null, then set anchorsToPopUps[anchor] to hintShowing.

  6. Let popUpPositions be an empty map.

  7. Let index be 0.

  8. For each popUp in document's auto pop-up stack:

    1. Set popUpPositions[popUp] to index.

    2. Increment index by 1.

  9. If hintShowing is not null, then:

    1. Set popUpPositions[hintShowing] to index.

    2. Increment index by 1.

  10. If ancestorType is "new-pop-up", then:

    1. Set popUpPositions[node] to index.

  11. Let upperBound be 2147483647.

  12. If popUpPositions[node] exists, then set upperBound to popUpPositions[node].

  13. If hintShowing is not null and ancestorType is "new-pop-up", then set upperBound to popUpPositions[hintShowing].

  14. If ancestorType is "inclusive", then:

    1. Let currentNode be node.

    2. While currentNode has a parent node within the flat tree:

      1. If currentNode's popup attribute is not in the no pop-up state and currentNode's pop-up visibility state is showing and currentNode's popup attribute is not in the manual state, then:

        1. If popUpPositions[currentNode] + 1 is greater than upperBound, then set upperBound to popUpPositions[currentNode] + 1.

      2. Let targetPopUp be currentNode's pop-up target element.

      3. If targetPopUp's popup attribute is not null and targetPopUp's pop-up visibility state is showing and targetPopUp's popup attribute is not in the manual state, then:

        1. If popUpPositions[targetPopUp] + 1 is greater than upperBound, then set upperBound to popUpPositions[targetPopUp] + 1.

      4. Set currentNode to the parent node of currentNode within the flat tree.

  15. Let seen be an empty set.

  16. Return the result of finding the nearest open ancestral pop-up recursively given node, popUpPositions, anchorsToPopUps, upperBound, and seen.

To find the nearest open ancestral pop-up recursively, given a Node node, a map popUpPositions, a map anchorsToPopUps, an integer upperBound, and a set seen, perform the following steps. They return an Element or null.

  1. If node is null, then return null.

  2. If seen contains node, then return null.

  3. Add node to seen.

  4. Let ancestor be null.

  5. Let position be −1.

  6. Let update be an algorithm which performs the following steps given popUp:

    1. If popUp is not null and popUp's pop-up visibility state is not showing and popUp's popup attribute is not in the manual state, then:

      1. Let newPosition be popUpPositions[popUp].

      2. If newPosition is greater than position and newPosition is less than upperBound, then:

        1. Set ancestor to popUp.

        2. Set position to newPosition.

  7. Let recurseAndUpdate be an algorithm which performs the following steps given node:

    1. Let nearestOpenAncestor be the result of finding the nearest open ancestral pop-up recursively given node, popUpPositions, anchorsToPopUps, upperBound, and seen.

    2. Run update given nearestOpenAncestor.

  8. Run update given node.

  9. If popUpPositions[node] exists, then:

    1. Run recurseAndUpdate given node's pop-up anchor element.

    2. Run recurseAndUpdate given node's pop-up invoker.

  10. If node has a pop-up target element, then run recurseAndUpdate given node's pop-up target element.

  11. If anchorsToPopUps[node] exists, then run recurseAndUpdate given anchorsToPopUps[node].

  12. Run recurseAndUpdate given node's parent node in the flat tree.

  13. Return ancestor.

To get the pop-up anchor element of an Element element, perform the following steps. They return an Element or null.

  1. If element's popup attribute is in the no pop-up state, then return null.

  2. Let anchorAttribute be the result of running get an attribute by name given element and anchor.

  3. If anchorAttribute is null, then return null.

  4. Return the first element, in tree order, within element's root's descendants, whose ID is anchorAttribute; otherwise, if there is no such element, null.

To find the topmost pop-up auto or hint given a Document document, perform the following steps. They return an Element or null.

  1. If document's currently-showing hint pop-up is not null, then return document's currently-showing hint pop-up.

  2. If document's auto pop-up stack is not empty, then return document's auto pop-up stack's last element.

  3. Return null.

To perform the pop-up focusing steps for an Element subject:

  1. Let control be the result of running pop-up focusable area given subject.

  2. If control is null, then return.

  3. Run the focusing steps given control.

  4. Let topDocument be the active document of control's node document's browsing context's top-level browsing context.

  5. If control's node document's origin is not the same as the origin of topDocument, then return.

  6. Empty topDocument's autofocus candidates.

  7. Set topDocument's autofocus processed flag to true.

To get the pop-up focusable area given an element subject, perform the following steps. They return an Element or null.

  1. If subject has the autofocus attribute, then return subject.

  2. For each node in the flat tree within subject:

    1. If node is a dialog element or node's popup attribute is not in the no pop-up state, then continue without traversing into the child nodes of node.

    2. If node is not focusable, then continue.

    3. If node does not have the autofocus attribute, then continue.

    4. Return node.

  3. Return null.

6.11.1 The pop-up target attributes

Supported elements may have the following content attributes, known as the pop-up target attributes:

The pop-up target attributes allow certain types of buttons to show and hide element with the popup attribute. If a pop-up target attribute is specified, then that attribute's value must be the ID of element with the popup attribute.

The following shows how popupshowtarget can be used to open a pop-up:

<div popup=auto id="foo">
  This is a pop-up!
</div>

<button popupshowtarget="foo">
  Show a pop-up
</button>

The following shows how popuptoggletarget can open and close a manual pop-up, which can't be closed with light dismiss:

<div popup=manual id="foo">
  This is a pop-up!
</div>

<button popuptoggletarget="foo">
  Show or hide a pop-up
</button>

The pop-up target attributes are only supported on the following elements:

DOM interface:

The popUpToggleTarget IDL attribute must reflect the popuptoggletarget attribute.

The popUpHideTarget IDL attribute must reflect the popuphidetarget attribute.

The popUpShowTarget IDL attribute must reflect the popupshowtarget attribute.

To run the pop-up target attribute activation behavior given a Node node:

  1. If node is disabled, then return.

  2. If node is not supported by the pop-up target attributes, then return.

  3. Let popUp be node's pop-up target element.

  4. If popUp is null, then return.

  5. If node doesn't have the popuptoggletarget attribute, then:

    1. If node has the popupshowtarget attribute and popUp's pop-up visibility state is showing, then return.

    2. If node has the popuphidetarget attribute and popUp's pop-up visibility state is hidden, then return.

    3. If node doesn't have the popupshowtarget attribute and node doesn't have the popuphidetarget attribute, then return.

  6. If node has a form owner and node is in any of the following states, then return:

  7. If popUp's pop-up visibility state is showing, then run the hide pop-up algorithm given popUp, true, and false.

  8. Otherwise:

    1. Set popUp's pop-up invoker to node.

    2. Run show pop-up given popUp.

To get the pop-up target element given a Node node, perform the following steps. They return an Element or null.

  1. If node is not supported, then return null.

  2. Let idref be null.

  3. If node has the popuptoggletarget attribute, then set idref to the value of node's popuptoggletarget attribute.

  4. Otherwise, if node has the popupshowtarget attribute, then set idref to the value of node's popupshowtarget attribute.

  5. Otherwise, if node has the popuphidetarget attribute, then set idref to the value of node's popuphidetarget attribute.

  6. If idref is null, then return null.

  7. Let popupElement be the first element, in tree order, within node's root's descendants, whose ID is idref; otherwise, if there is no such element, null.

  8. If popupElement is null, then return null.

  9. If popupElement's popup attribute is in the no pop-up state, then return null.

  10. Return popupElement.

6.11.2 Pop-up light dismiss

"Light dismiss" means that pressing the Esc key or clicking outside of a pop-up whose popup attribute is in the auto or hint states will close the pop-up.

When a Document document receives an Event event in the capture phase:

  1. Let topmostPopup be the result of running topmost pop-up auto or hint given document.

  2. If topmostPopup is null, then return.

  3. Let target be event's target.

  4. If event is a mousedown event, then:

    1. Set document's pop-up mousedown target to the result of running nearest open ancestral pop-up given target and "inclusive".

  5. If event is a mouseup event, then:

    1. Let ancestor be the result of running nearest open ancestral pop-up given target and "inclusive".

    2. Let sameTarget be true if ancestor is document's pop-up mousedown target.

    3. Set document's pop-up mousedown target to null.

    4. If sameTarget is true, then run hide all pop-ups until given ancestor, false, false, and true.

  6. If event is a keydown event for the Escape key, then:

    1. Run the hide pop-up algorithm given topmostPopup, true, and false.

6.11.3 The defaultopen attribute

All elements may have the defaultopen content attribute set. When specified on an element whose popup attribute is not in the no pop-up state, it makes the element shown automatically when the page is loaded. defaultopen is a boolean attribute.

The defaultOpen IDL attribute must reflect the defaultopen content attribute.

6.11.4 The anchor attribute

All elements may have the anchor attribute set. When specified on an element whose popup attribute is not in the no pop-up state, the value of the attribute is used as an ID to refer to another element. If the other element's popup attribute is also not in the no pop-up state, then the other element is considered to be a parent in the pop-up hierarchy. This means, for example, that if the element and parent element's popup attributes are in the auto state, then both of them can be open at the same time even though only one auto pop-up is supposed to be open at a time.