diff --git a/files/en-us/glossary/top_layer/index.md b/files/en-us/glossary/top_layer/index.md
new file mode 100644
index 000000000000000..134eedd3a51b4db
--- /dev/null
+++ b/files/en-us/glossary/top_layer/index.md
@@ -0,0 +1,23 @@
+---
+title: Top layer
+slug: Glossary/Top_layer
+page-type: glossary-definition
+---
+
+The **top layer** is a specific layer in the [stacking context](/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context), which spans the entire width and height of the viewport and sits on top of all other layers displayed in a web document. It is created by the browser to contain elements that should appear on top of all other content on the page.
+
+Elements that will appear in the top layer include:
+
+- Fullscreen elements, i.e. elements that have been caused to display in fullscreen mode by a successful {{domxref("Element.requestFullscreen()")}} call.
+- {{htmlelement("dialog")}} elements displayed as a modal via a successful {{domxref("HTMLDialogElement.showModal()")}} call.
+- Popover elements shown via a successful {{domxref("HTMLElement.showPopover()")}} call.
+
+The following screenshot demonstrates how a shown popover element is placed in the top layer in Chrome:
+
+![An element in the top layer, as shown in the chrome devtools](top_layer_devtools.png)
+
+## See also
+
+- [The stacking context](/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context)
+- [The Fullscreen API](/en-US/docs/Web/API/Fullscreen_API)
+- [The Popover API](/en-US/docs/Web/API/Popover_API)
diff --git a/files/en-us/glossary/top_layer/top_layer_devtools.png b/files/en-us/glossary/top_layer/top_layer_devtools.png
new file mode 100644
index 000000000000000..48e2e455774ba9f
Binary files /dev/null and b/files/en-us/glossary/top_layer/top_layer_devtools.png differ
diff --git a/files/en-us/web/api/element/requestfullscreen/index.md b/files/en-us/web/api/element/requestfullscreen/index.md
index 089f53f8ca663bb..8236bc72f598804 100644
--- a/files/en-us/web/api/element/requestfullscreen/index.md
+++ b/files/en-us/web/api/element/requestfullscreen/index.md
@@ -66,6 +66,7 @@ returned. The rejection handler receives one of the following exception values:_
- The element is not permitted to use the `fullscreen` feature,
either because of [Permissions Policy](/en-US/docs/Web/HTTP/Permissions_Policy) configuration or other access control features.
- The element and its document are the same node.
+ - The element is a [popover](/en-US/docs/Web/API/Popover_API) that is already being shown via {{domxref("HTMLElement.showPopover()")}}.
## Security
diff --git a/files/en-us/web/api/htmlbuttonelement/index.md b/files/en-us/web/api/htmlbuttonelement/index.md
index 59f8f0b0f949b49..ddd05091b56393d 100644
--- a/files/en-us/web/api/htmlbuttonelement/index.md
+++ b/files/en-us/web/api/htmlbuttonelement/index.md
@@ -40,6 +40,10 @@ _Inherits properties from its parent, {{domxref("HTMLElement")}}._
- : A {{domxref("HTMLMenuElement")}} representing the menu element to be displayed if the button is clicked and is of `type="menu"`.
- {{domxref("HTMLButtonElement.name")}}
- : A string representing the name of the object when submitted with a form. If specified, it must not be the empty string.
+- {{domxref("HTMLButtonElement.popoverTargetAction")}}
+ - : Gets and sets the action to be performed (`"hide"`, `"show"`, or `"toggle"`) on a popover element being controlled by a control button. It reflects the value of the [`popovertargetaction`](/en-US/docs/Web/HTML/Element/button#popovertargetaction) HTML attribute.
+- {{domxref("HTMLButtonElement.popoverTargetElement")}}
+ - : Gets and sets the popover element to control via a button. The JavaScript equivalent of the [`popovertarget`](/en-US/docs/Web/HTML/Element/button#popovertarget) HTML attribute.
- {{domxref("HTMLButtonElement.tabIndex")}}
- : A `long` that represents this element's position in the tabbing order.
- {{domxref("HTMLButtonElement.type")}}
diff --git a/files/en-us/web/api/htmlbuttonelement/popovertargetaction/index.md b/files/en-us/web/api/htmlbuttonelement/popovertargetaction/index.md
new file mode 100644
index 000000000000000..ae5751fa0b20e28
--- /dev/null
+++ b/files/en-us/web/api/htmlbuttonelement/popovertargetaction/index.md
@@ -0,0 +1,59 @@
+---
+title: "HTMLButtonElement: popoverTargetAction property"
+short-title: popoverTargetAction
+slug: Web/API/HTMLButtonElement/popoverTargetAction
+page-type: web-api-instance-property
+status:
+ - experimental
+browser-compat: api.HTMLButtonElement.popoverTargetAction
+---
+
+{{ APIRef("DOM") }}{{SeeCompatTable}}
+
+The **`popoverTargetAction`** property of the {{domxref("HTMLButtonElement")}} interface gets and sets the action to be performed (`"hide"`, `"show"`, or `"toggle"`) on a popover element being controlled by a control button.
+
+It reflects the value of the [`popovertargetaction`](/en-US/docs/Web/HTML/Element/button#popovertargetaction) HTML attribute.
+
+## Value
+
+An enumerated value. Possible values are:
+
+- `"hide"`
+ - : The button will hide a shown popover. If you try to hide an already hidden popover, no action will be taken.
+- `"show"`
+ - : The button will show a hidden popover. If you try to show an already showing popover, no action will be taken.
+- `"toggle"`
+ - : The button will toggle a popover between showing and hidden. if the popover is hidden, it will be shown; if the popover is showing, it will be hidden. If `popoverTargetAction` is not set, `"toggle"` is the default action that will be performed by the control button.
+
+## Examples
+
+```js
+function supportsPopover() {
+ return HTMLElement.prototype.hasOwnProperty("popover");
+}
+
+const popover = document.getElementById("mypopover");
+const toggleBtn = document.getElementById("toggleBtn");
+
+const popoverSupported = supportsPopover();
+
+if (popoverSupported) {
+ popover.popover = "auto";
+ toggleBtn.popoverTargetElement = popover;
+ toggleBtn.popoverTargetAction = "toggle";
+} else {
+ console.log("Popover API not supported.");
+}
+```
+
+## Specifications
+
+{{Specifications}}
+
+## Browser compatibility
+
+{{Compat}}
+
+## See also
+
+- [Popover API](/en-US/docs/Web/API/Popover_API)
diff --git a/files/en-us/web/api/htmlbuttonelement/popovertargetelement/index.md b/files/en-us/web/api/htmlbuttonelement/popovertargetelement/index.md
new file mode 100644
index 000000000000000..79fe90a4e4da158
--- /dev/null
+++ b/files/en-us/web/api/htmlbuttonelement/popovertargetelement/index.md
@@ -0,0 +1,52 @@
+---
+title: "HTMLButtonElement: popoverTargetElement property"
+short-title: popoverTargetElement
+slug: Web/API/HTMLButtonElement/popoverTargetElement
+page-type: web-api-instance-property
+status:
+ - experimental
+browser-compat: api.HTMLButtonElement.popoverTargetElement
+---
+
+{{ APIRef("DOM") }}{{SeeCompatTable}}
+
+The **`popoverTargetElement`** property of the {{domxref("HTMLButtonElement")}} interface gets and sets the popover element to control via a control button.
+
+It is the JavaScript equivalent of the [`popovertarget`](/en-US/docs/Web/HTML/Element/button#popovertarget) HTML attribute.
+
+## Value
+
+A reference to a popover element in the DOM.
+
+## Examples
+
+```js
+function supportsPopover() {
+ return HTMLElement.prototype.hasOwnProperty("popover");
+}
+
+const popover = document.getElementById("mypopover");
+const toggleBtn = document.getElementById("toggleBtn");
+
+const popoverSupported = supportsPopover();
+
+if (popoverSupported) {
+ popover.popover = "auto";
+ toggleBtn.popoverTargetElement = popover;
+ toggleBtn.popoverTargetAction = "toggle";
+} else {
+ console.log("Popover API not supported.");
+}
+```
+
+## Specifications
+
+{{Specifications}}
+
+## Browser compatibility
+
+{{Compat}}
+
+## See also
+
+- [Popover API](/en-US/docs/Web/API/Popover_API)
diff --git a/files/en-us/web/api/htmldetailselement/toggle_event/index.md b/files/en-us/web/api/htmldetailselement/toggle_event/index.md
index 5b9debf3c5cd75e..7bfe0460883a8d2 100644
--- a/files/en-us/web/api/htmldetailselement/toggle_event/index.md
+++ b/files/en-us/web/api/htmldetailselement/toggle_event/index.md
@@ -12,6 +12,8 @@ The **`toggle`** event fires when the `open`/`closed` state of a {{HtmlElement("
This event is not cancelable and does not bubble.
+> **Note:** The `toggle` event is also available in a different form on {{domxref("HTMLElement")}}; this version fires on [popover elements](/en-US/docs/Web/API/Popover_API) just after they are shown or hidden. See the `HTMLElement` {{domxref("HTMLElement.toggle_event", "toggle event")}} page for more information.
+
## Syntax
Use the event name in methods like {{domxref("EventTarget.addEventListener", "addEventListener()")}}, or set an event handler property.
diff --git a/files/en-us/web/api/htmldialogelement/showmodal/index.md b/files/en-us/web/api/htmldialogelement/showmodal/index.md
index 512540163b0c3c1..8cd4148c1e4ab63 100644
--- a/files/en-us/web/api/htmldialogelement/showmodal/index.md
+++ b/files/en-us/web/api/htmldialogelement/showmodal/index.md
@@ -10,7 +10,7 @@ browser-compat: api.HTMLDialogElement.showModal
The **`showModal()`** method of the
{{domxref("HTMLDialogElement")}} interface displays the dialog as a modal, over the top
-of any other dialogs that might be present. It displays into the top layer, along with a
+of any other dialogs that might be present. It displays in the {{glossary("top layer")}}, along with a
{{cssxref('::backdrop')}} pseudo-element. Interaction outside the dialog is blocked and
the content outside it is rendered inert.
@@ -31,7 +31,7 @@ None ({{jsxref("undefined")}}).
### Exceptions
- `InvalidStateError` {{domxref("DOMException")}}
- - : Thrown if the dialog is already open (i.e. if the `open` attribute is already set on the {{htmlelement("dialog")}} element).
+ - : Thrown if the dialog is already open (i.e. if the `open` attribute is already set on the {{htmlelement("dialog")}} element), or if the dialog is also a [popover](/en-US/docs/Web/API/Popover_API) that is already being shown.
## Examples
diff --git a/files/en-us/web/api/htmlelement/beforetoggle_event/index.md b/files/en-us/web/api/htmlelement/beforetoggle_event/index.md
index 412d9191c632b35..83421e59fbba797 100644
--- a/files/en-us/web/api/htmlelement/beforetoggle_event/index.md
+++ b/files/en-us/web/api/htmlelement/beforetoggle_event/index.md
@@ -9,9 +9,10 @@ browser-compat: api.HTMLElement.beforetoggle_event
{{APIRef}}{{SeeCompatTable}}
-The **`beforetoggle`** event fires when an element with the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute is about to be opened or closed.
+The **`beforetoggle`** event of the {{domxref("HTMLElement")}} interface fires on a {{domxref("Popover_API", "popover", "", "nocode")}} element (i.e. one that has a valid [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute) just before it is shown or hidden.
-If the element is currently not open, then the `.oldState` property will be set to `closed` and the `.newState` property will be set to `open`; otherwise if the element is open, then `.oldState` will be `open` and `.newState` will be `closed`.
+- If the popover is transitioning from hidden to showing, the `event.oldState` property will be set to `closed` and the `event.newState` property will be set to `open`.
+- If the popover is transitioning from showing to hidden, then `event.oldState` will be `open` and `event.newState` will be `closed`.
## Syntax
@@ -29,14 +30,39 @@ A {{domxref("ToggleEvent")}}. Inherits from {{domxref("Event")}}.
{{InheritanceDiagram("ToggleEvent")}}
-## Event properties
+## Examples
-_This interface inherits properties from its parent {{DOMxRef("Event")}}._
+### Basic example
-- {{DOMxRef("ToggleEvent.oldState")}} {{ReadOnlyInline}}
- - : Returns either `open` or `closed`, depending on which state the element is transitioning from.
-- {{DOMxRef("ToggleEvent.newState")}} {{ReadOnlyInline}}
- - : Returns either `open` or `closed`, depending on which state the element is transitioning to.
+```js
+const popover = document.getElementById("mypopover");
+
+// ...
+
+popover.addEventListener("beforetoggle", (event) => {
+ if (event.newState === "open") {
+ console.log("Popover is being shown");
+ } else {
+ console.log("Popover is being hidden");
+ }
+});
+```
+
+### A note on toggle event coalescing
+
+It is worth pointing out that `beforetoggle` events are coalesced, meaning that if multiple `beforetoggle` events are fired before the event loop has a chance to cycle, only a single event will be fired.
+
+For example:
+
+```js
+popover.addEventListener('beforetoggle', () => {
+ //...
+});
+
+popover.showPopover();
+popover.hidePopover();
+// `beforetoggle` only fires once
+```
## Specifications
@@ -48,5 +74,5 @@ _This interface inherits properties from its parent {{DOMxRef("Event")}}._
## See also
+- [Popover API](/en-US/docs/Web/API/Popover_API)
- Related event: [`toggle`](/en-US/docs/Web/API/HTMLElement/toggle_event)
-- The [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute
diff --git a/files/en-us/web/api/htmlelement/hidepopover/index.md b/files/en-us/web/api/htmlelement/hidepopover/index.md
index 24ab9564752d174..866b130936bb318 100644
--- a/files/en-us/web/api/htmlelement/hidepopover/index.md
+++ b/files/en-us/web/api/htmlelement/hidepopover/index.md
@@ -10,9 +10,9 @@ browser-compat: api.HTMLElement.hidePopover
{{ APIRef("HTML DOM") }}{{SeeCompatTable}}
-The **`HTMLElement.hidePopover()`** method opens an element that has a valid [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute.
+The **`hidePopover()`** method of the {{domxref("HTMLElement")}} interface hides a {{domxref("Popover_API", "popover", "", "nocode")}} element (i.e. one that has a valid [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute) by removing it from the {{glossary("top layer")}} and styling it with `display: none`.
-When `hidePopover()` is called on an element with the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute that is currently open, then a {{domxref("HTMLElement/beforetoggle_event", "beforetoggle")}} non-cancelable event will be fired, followed by the popover closing, and a {{domxref("HTMLElement/toggle_event", "toggle")}} event will be fired. If the element is already closed, then nothing will happen.
+When `hidePopover()` is called on a showing element with the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute, a {{domxref("HTMLElement/beforetoggle_event", "beforetoggle")}} event will be fired, followed by the popover being hidden, and then the {{domxref("HTMLElement/toggle_event", "toggle")}} event firing. If the element is already hidden, an error is thrown.
## Syntax
@@ -28,24 +28,44 @@ None.
None ({{jsxref("undefined")}}).
+### Exceptions
+
+- `InvalidStateError` {{domxref("DOMException")}}
+ - : Thrown if the popover is already hidden.
+
## Examples
-Open a popover when moving the mouse pointer over a button:
+The following example provides functionality to hide a popover by pressing a particular key on the keyboard.
-### HTML
+First, some HTML:
```html
-
-
Popover
+
+
Help!
+
+
You can use the following commands to control the app
+
+
+
Press C to order cheese
+
Press T to order tofu
+
Press B to order bacon
+
+
Say "Service" to summon the robot waiter to take your order
+
Say "Escape" to engage the ejector seat
+
+
```
-### JavaScript
+And now the JavaScript to wire up the functionality:
```js
-// On mouse-over, execute myFunction
-function myFunction() {
- document.getElementById("myPopover").hidePopover();
-}
+const popover = document.getElementById("mypopover");
+
+document.addEventListener("keydown", (event) => {
+ if (event.key === "h") {
+ popover.hidePopover();
+ }
+});
```
## Specifications
@@ -58,12 +78,4 @@ function myFunction() {
## See also
-- Related event handlers
-
- - {{domxref("HTMLElement.beforetoggle_event", "HTMLElement.beforetoggle")}}
- - {{domxref("HTMLElement.toggle_event", "HTMLElement.toggle")}}
-
-- Related methods
-
- - {{domxref("HTMLElement.showPopover", "HTMLElement.showPopover")}}
- - {{domxref("HTMLElement.togglePopover", "HTMLElement.togglePopover")}}
+- [Popover API](/en-US/docs/Web/API/Popover_API)
diff --git a/files/en-us/web/api/htmlelement/index.md b/files/en-us/web/api/htmlelement/index.md
index 33e49a39498796d..5a812c5e3ecb0ef 100644
--- a/files/en-us/web/api/htmlelement/index.md
+++ b/files/en-us/web/api/htmlelement/index.md
@@ -43,8 +43,8 @@ _Inherits properties from its parent, {{DOMxRef("Element")}}._
As a setter, it replaces the content inside the selected element, converting any line breaks into {{HTMLElement("br")}} elements.
- {{DOMxRef("HTMLElement.inputMode")}}
- : A string value reflecting the value of the element's [`inputmode`](/en-US/docs/Web/HTML/Global_attributes/inputmode) attribute.
-- {{DOMxRef("HTMLElement.popover")}} {{Experimental_Inline}}
- - : A string value reflecting the value of the element's [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute.
+- {{domxref("HTMLElement.popover")}}
+ - : Gets and sets an element's popover state via JavaScript (`"auto"` or `"manual"`), and can be used for feature detection. Reflects the value of the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) global HTML attribute.
- {{DOMxRef("HTMLElement.lang")}}
- : A string representing the language of an element's attributes, text, and element contents.
- {{DOMxRef("HTMLElement.noModule")}}
@@ -91,11 +91,11 @@ _Inherits methods from its parent, {{DOMxRef("Element")}}._
- {{DOMxRef("HTMLElement.focus()")}}
- : Makes the element the current keyboard focus.
- {{DOMxRef("HTMLElement.hidePopover()")}} {{Experimental_Inline}}
- - : Hides the element, if it has a valid {{DOMxRef("HTMLElement.popover")}} value.
+ - : Hides a popover element by removing it from the {{glossary("top layer")}} and styling it with `display: none`.
- {{DOMxRef("HTMLElement.showPopover()")}} {{Experimental_Inline}}
- - : Shows the element, promoting it to the top layer, if it has a valid {{DOMxRef("HTMLElement.popover")}} value.
+ - : Shows a popover element by adding it to the {{glossary("top layer")}} and removing `display: none;` from its styles.
- {{DOMxRef("HTMLElement.togglePopover()")}} {{Experimental_Inline}}
- - : Hides or shows the element, if it has a valid {{DOMxRef("HTMLElement.popover")}} value.
+ - : Toggles a popover element between the hidden and showing states.
## Events
diff --git a/files/en-us/web/api/htmlelement/popover/index.md b/files/en-us/web/api/htmlelement/popover/index.md
new file mode 100644
index 000000000000000..ab6d08245b3e345
--- /dev/null
+++ b/files/en-us/web/api/htmlelement/popover/index.md
@@ -0,0 +1,67 @@
+---
+title: "HTMLElement: popover property"
+short-title: popover
+slug: Web/API/HTMLElement/popover
+page-type: web-api-instance-property
+status:
+ - experimental
+browser-compat: api.HTMLElement.popover
+---
+
+{{ APIRef("HTML DOM") }}{{SeeCompatTable}}
+
+The **`popover`** property of the {{domxref("HTMLElement")}} interface gets and sets an element's popover state via JavaScript (`"auto"` or `"manual"`), and can be used for feature detection.
+
+It reflects the value of the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) global HTML attribute.
+
+## Value
+
+An enumerated value; possible values are:
+
+- `"auto"`: In [auto state](/en-US/docs/Web/API/Popover_API/Using#auto_state_and_light_dismiss):
+ - The popover can be "light dismissed" — this means that you can hide the popover by clicking outside it or pressing the Esc key.
+ - Usually, only one popover can be shown at a time — showing a second popover when one is already shown will hide the first one. The exception to this rule is when you have nested auto popovers. See [Nested popovers](/en-US/docs/Web/API/Popover_API/Using#nested_popovers) for more details.
+- `"manual"`: In [manual state](/en-US/docs/Web/API/Popover_API/Using#using_manual_popover_state):
+ - The popover cannot be "light dismissed", although declarative show/hide/toggle buttons will still work.
+ - Multiple independent popovers can be shown at a time.
+
+## Examples
+
+### Feature detection
+
+You can use the `popover` attribute to feature detect the [Popover API](/en-US/docs/Web/API/Popover_API):
+
+```js
+function supportsPopover() {
+ return HTMLElement.prototype.hasOwnProperty("popover");
+}
+```
+
+### Setting up a popover programmatically
+
+```js
+const popover = document.getElementById("mypopover");
+const toggleBtn = document.getElementById("toggleBtn");
+
+const popoverSupported = supportsPopover();
+
+if (popoverSupported) {
+ popover.popover = "auto";
+ toggleBtn.popoverTargetElement = popover;
+ toggleBtn.popoverTargetAction = "toggle";
+} else {
+ console.log("Popover API not supported.");
+}
+```
+
+## Specifications
+
+{{Specifications}}
+
+## Browser compatibility
+
+{{Compat}}
+
+## See also
+
+- [Popover API](/en-US/docs/Web/API/Popover_API)
diff --git a/files/en-us/web/api/htmlelement/showpopover/index.md b/files/en-us/web/api/htmlelement/showpopover/index.md
index bea15ed6ad8b618..1a364aee4a7165f 100644
--- a/files/en-us/web/api/htmlelement/showpopover/index.md
+++ b/files/en-us/web/api/htmlelement/showpopover/index.md
@@ -10,10 +10,9 @@ browser-compat: api.HTMLElement.showPopover
{{ APIRef("HTML DOM") }}{{SeeCompatTable}}
-The **`HTMLElement.showPopover()`** method opens an element that has a valid [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute.
+The **`showPopover()`** method of the {{domxref("HTMLElement")}} interface shows a {{domxref("Popover_API", "popover", "", "nocode")}} element (i.e. one that has a valid [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute) by adding it to the {{glossary("top layer")}}.
-When `showPopover()` is called on an element with the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute that is currently hidden, then a {{domxref("HTMLElement/beforetoggle_event", "beforetoggle")}} cancelable event will be fired followed by the popover opening and a {{domxref("HTMLElement/toggle_event", "toggle")}} event being fired.
-If the element is already open, then nothing will happen.
+When `showPopover()` is called on an element with the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute that is currently hidden, a {{domxref("HTMLElement/beforetoggle_event", "beforetoggle")}} event will be fired, followed by the popover showing, and then the {{domxref("HTMLElement/toggle_event", "toggle")}} event firing. If the element is already showing, an error will be thrown.
## Syntax
@@ -29,6 +28,46 @@ None.
None ({{jsxref("undefined")}}).
+### Exceptions
+
+- `InvalidStateError` {{domxref("DOMException")}}
+ - : Thrown if the popover is already showing.
+
+## Examples
+
+The following example provides functionality to show a popover by pressing a particular key on the keyboard.
+
+First, some HTML:
+
+```html
+
+
Help!
+
+
You can use the following commands to control the app
+
+
+
Press C to order cheese
+
Press T to order tofu
+
Press B to order bacon
+
+
Say "Service" to summon the robot waiter to take your order
+
Say "Escape" to engage the ejector seat
+
+
+```
+
+And now the JavaScript to wire up the functionality:
+
+```js
+const popover = document.getElementById("mypopover");
+
+document.addEventListener("keydown", (event) => {
+ if (event.key === "h") {
+ popover.showPopover();
+ }
+});
+```
+
## Specifications
{{Specifications}}
@@ -39,12 +78,4 @@ None ({{jsxref("undefined")}}).
## See also
-- Related event handlers
-
- - {{domxref("HTMLElement.beforetoggle_event", "HTMLElement.beforetoggle")}}
- - {{domxref("HTMLElement.toggle_event", "HTMLElement.toggle")}}
-
-- Related methods
-
- - {{domxref("HTMLElement.hidePopover", "HTMLElement.hidePopover")}}
- - {{domxref("HTMLElement.togglePopover", "HTMLElement.togglePopover")}}
+- [Popover API](/en-US/docs/Web/API/Popover_API)
diff --git a/files/en-us/web/api/htmlelement/toggle_event/index.md b/files/en-us/web/api/htmlelement/toggle_event/index.md
index faea9cd6b6722f4..d00fd00ad9e66ab 100644
--- a/files/en-us/web/api/htmlelement/toggle_event/index.md
+++ b/files/en-us/web/api/htmlelement/toggle_event/index.md
@@ -9,9 +9,12 @@ browser-compat: api.HTMLElement.toggle_event
{{APIRef}}{{SeeCompatTable}}
-The **`toggle`** event fires when an element with the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute is about to be opened or closed.
+The **`toggle`** event of the {{domxref("HTMLElement")}} interface fires on a {{domxref("Popover_API", "popover", "", "nocode")}} element (i.e. one that has a valid [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute) just after it is shown or hidden.
-If the element is currently not open, then the `.oldState` property will be set to `closed` and the `.newState` property will be set to `open`; otherwise if the element is open then `.oldState` will be `open` and `.newState` will be `closed`.
+- If the popover element is transitioning from hidden to showing, the `event.oldState` property will be set to `closed` and the `event.newState` property will be set to `open`.
+- If the popover element is transitioning from showing to hidden, then `event.oldState` will be `open` and `event.newState` will be `closed`.
+
+> **Note:** The `toggle` event behaves differently when fired on {{htmlelement("details")}} elements. In this case, it does not relate to popovers, and instead fires when the `open`/`closed` state of a `` element is toggled. See the `HTMLDetailsElement` {{domxref("HTMLDetailsElement.toggle_event", "toggle event")}} page for more information.
## Syntax
@@ -29,14 +32,39 @@ A {{domxref("ToggleEvent")}}. Inherits from {{domxref("Event")}}.
{{InheritanceDiagram("ToggleEvent")}}
-## Event properties
+## Examples
+
+### Basic example
+
+```js
+const popover = document.getElementById("mypopover");
+
+// ...
+
+popover.addEventListener("toggle", (event) => {
+ if (event.newState === "open") {
+ console.log("Popover has been shown");
+ } else {
+ console.log("Popover has been hidden");
+ }
+});
+```
+
+### A note on toggle event coalescing
+
+It is worth pointing out that `toggle` events are coalesced, meaning that if multiple `toggle` events are fired before the event loop has a chance to cycle, only a single event will be fired.
-_This interface inherits properties from its parent {{DOMxRef("Event")}}._
+For example:
-- {{DOMxRef("ToggleEvent.oldState")}} {{ReadOnlyInline}}
- - : Returns either `open` or `closed`, depending on which state the element is transitioning from.
-- {{DOMxRef("ToggleEvent.newState")}} {{ReadOnlyInline}}
- - : Returns either `open` or `closed`, depending on which state the element is transitioning to.
+```js
+popover.addEventListener('toggle', () => {
+ //...
+});
+
+popover.showPopover();
+popover.hidePopover();
+// `toggle` only fires once
+```
## Specifications
@@ -48,5 +76,5 @@ _This interface inherits properties from its parent {{DOMxRef("Event")}}._
## See also
+- [Popover API](/en-US/docs/Web/API/Popover_API)
- Related event: [`beforetoggle`](/en-US/docs/Web/API/HTMLElement/beforetoggle_event)
-- The [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute
diff --git a/files/en-us/web/api/htmlelement/togglepopover/index.md b/files/en-us/web/api/htmlelement/togglepopover/index.md
index 28b843032389e0d..cbce5f2112df16f 100644
--- a/files/en-us/web/api/htmlelement/togglepopover/index.md
+++ b/files/en-us/web/api/htmlelement/togglepopover/index.md
@@ -10,26 +10,68 @@ browser-compat: api.HTMLElement.togglePopover
{{ APIRef("HTML DOM") }}{{SeeCompatTable}}
-The **`HTMLElement.togglePopover()`** method opens an element that has a valid [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute.
+The **`togglePopover()`** method of the {{domxref("HTMLElement")}} interface toggles a {{domxref("Popover_API", "popover", "", "nocode")}} element (i.e. one that has a valid [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute) between the hidden and showing states.
-When `togglePopover()` is called on an element with the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute that is currently hidden, then a {{domxref("HTMLElement/beforetoggle_event", "beforetoggle")}} cancelable event will be fired, followed by the popover opening and a {{domxref("HTMLElement/toggle_event", "toggle")}} event being fired.
+When `togglePopover()` is called on an element with the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute:
-If the element is already open, then a {{domxref("HTMLElement/beforetoggle_event", "beforetoggle")}} non-cancelable event will be fired followed by the popover closing and a {{domxref("HTMLElement/toggle_event", "toggle")}} event being fired.
+1. A {{domxref("HTMLElement/beforetoggle_event", "beforetoggle")}} event is fired.
+2. The popover toggles between hidden and showing:
+ 1. If it was initially showing, it toggles to hidden.
+ 2. If it was initially hidden, it toggles to showing.
+3. A {{domxref("HTMLElement/toggle_event", "toggle")}} event is fired.
## Syntax
```js-nolint
-togglePopover()
+togglePopover(force)
```
### Parameters
-None.
+- `force`
+ - : A boolean, which causes `togglePopover()` to behave like {{domxref("HTMLElement.showPopover", "showPopover()")}} or {{domxref("HTMLElement.hidePopover", "hidePopover()")}}, except that it doesn't throw an exception if the popover is already in the target state.
+ - If set to `true`, the popover is shown if it was initially hidden. If it was initially shown, nothing happens.
+ - If set to `false`, the popover is hidden if it was initially shown. If it was initially hidden, nothing happens.
### Return value
None ({{jsxref("undefined")}}).
+## Examples
+
+The following example provides functionality to toggle a popover on and off by pressing a particular key on the keyboard.
+
+First, some HTML:
+
+```html
+
+
Help!
+
+
You can use the following commands to control the app
+
+
+
Press C to order cheese
+
Press T to order tofu
+
Press B to order bacon
+
+
Say "Service" to summon the robot waiter to take your order
+
Say "Escape" to engage the ejector seat
+
+
+```
+
+And now the JavaScript to wire up the functionality:
+
+```js
+const popover = document.getElementById("mypopover");
+
+document.addEventListener("keydown", (event) => {
+ if (event.key === "h") {
+ popover.togglePopover();
+ }
+});
+```
+
## Specifications
{{Specifications}}
@@ -40,12 +82,4 @@ None ({{jsxref("undefined")}}).
## See also
-- Related event handlers
-
- - {{domxref("HTMLElement.beforetoggle_event", "HTMLElement.beforetoggle")}}
- - {{domxref("HTMLElement.toggle_event", "HTMLElement.toggle")}}
-
-- Related methods
-
- - {{domxref("HTMLElement.hidePopover", "HTMLElement.hidePopover")}}
- - {{domxref("HTMLElement.showPopover", "HTMLElement.showPopover")}}
+- [Popover API](/en-US/docs/Web/API/Popover_API)
diff --git a/files/en-us/web/api/htmlinputelement/index.md b/files/en-us/web/api/htmlinputelement/index.md
index 5d67ab04b10f12a..e3a9ef114097dc9 100644
--- a/files/en-us/web/api/htmlinputelement/index.md
+++ b/files/en-us/web/api/htmlinputelement/index.md
@@ -51,6 +51,14 @@ Some properties only apply to input element types that support the corresponding
- : `string`: **Returns / Sets** the element's [`name`](/en-US/docs/Web/HTML/Element/input#name) attribute, containing a name that identifies the element when submitting the form.
+- {{domxref("HTMLInputElement.popoverTargetAction", "popoverTargetAction")}}
+
+ - : Gets and sets the action to be performed (`"hide"`, `"show"`, or `"toggle"`) on a popover element being controlled by an {{htmlelement("input")}} element of `type="button"`. It reflects the value of the [`popovertargetaction`](/en-US/docs/Web/HTML/Element/input#popovertargetaction) HTML attribute.
+
+- {{domxref("HTMLInputElement.popoverTargetElement", "popoverTargetElement")}}
+
+ - : Gets and sets the popover element to control via an {{htmlelement("input")}} element of `type="button"`. The JavaScript equivalent of the [`popovertarget`](/en-US/docs/Web/HTML/Element/input#popovertarget) HTML attribute.
+
- {{domxref("HTMLInputElement.step", "step")}}
- : `string`: **Returns / Sets** the element's [`step`](/en-US/docs/Web/HTML/Element/input#step) attribute, which works with [`min`](/en-US/docs/Web/HTML/Element/input#min) and [`max`](/en-US/docs/Web/HTML/Element/input#max) to limit the increments at which a numeric or date-time value can be set. It can be the string `any` or a positive floating point number. If this is not set to `any`, the control accepts only values at multiples of the step value greater than the minimum.
diff --git a/files/en-us/web/api/htmlinputelement/popovertargetaction/index.md b/files/en-us/web/api/htmlinputelement/popovertargetaction/index.md
new file mode 100644
index 000000000000000..38ac21245f05fd5
--- /dev/null
+++ b/files/en-us/web/api/htmlinputelement/popovertargetaction/index.md
@@ -0,0 +1,59 @@
+---
+title: "HTMLInputElement: popoverTargetAction property"
+short-title: popoverTargetAction
+slug: Web/API/HTMLInputElement/popoverTargetAction
+page-type: web-api-instance-property
+status:
+ - experimental
+browser-compat: api.HTMLInputElement.popoverTargetAction
+---
+
+{{ APIRef("DOM") }}{{SeeCompatTable}}
+
+The **`popoverTargetAction`** property of the {{domxref("HTMLInputElement")}} interface gets and sets the action to be performed (`"hide"`, `"show"`, or `"toggle"`) on a popover element being controlled by an {{htmlelement("input")}} element of `type="button"`.
+
+It reflects the value of the [`popovertargetaction`](/en-US/docs/Web/HTML/Element/button#popovertargetaction) HTML attribute.
+
+## Value
+
+An enumerated value. Possible values are:
+
+- `"hide"`
+ - : The button will hide a shown popover. If you try to hide an already hidden popover, no action will be taken.
+- `"show"`
+ - : The button will show a hidden popover. If you try to show an already showing popover, no action will be taken.
+- `"toggle"`
+ - : The button will toggle a popover between showing and hidden. If the popover is hidden, it will be shown; if the popover is showing, it will be hidden. If `popoverTargetAction` is not set, `"toggle"` is the default action that will be performed by the control button.
+
+## Examples
+
+```js
+function supportsPopover() {
+ return HTMLElement.prototype.hasOwnProperty("popover");
+}
+
+const popover = document.getElementById("mypopover");
+const toggleBtn = document.getElementById("toggleBtn");
+
+const popoverSupported = supportsPopover();
+
+if (popoverSupported) {
+ popover.popover = "auto";
+ toggleBtn.popoverTargetElement = popover;
+ toggleBtn.popoverTargetAction = "toggle";
+} else {
+ console.log("Popover API not supported.");
+}
+```
+
+## Specifications
+
+{{Specifications}}
+
+## Browser compatibility
+
+{{Compat}}
+
+## See also
+
+- [Popover API](/en-US/docs/Web/API/Popover_API)
diff --git a/files/en-us/web/api/htmlinputelement/popovertargetelement/index.md b/files/en-us/web/api/htmlinputelement/popovertargetelement/index.md
new file mode 100644
index 000000000000000..2739a42f09e21f2
--- /dev/null
+++ b/files/en-us/web/api/htmlinputelement/popovertargetelement/index.md
@@ -0,0 +1,52 @@
+---
+title: "HTMLInputElement: popoverTargetElement property"
+short-title: popoverTargetElement
+slug: Web/API/HTMLInputElement/popoverTargetElement
+page-type: web-api-instance-property
+status:
+ - experimental
+browser-compat: api.HTMLInputElement.popoverTargetElement
+---
+
+{{ APIRef("DOM") }}{{SeeCompatTable}}
+
+The **`popoverTargetElement`** property of the {{domxref("HTMLInputElement")}} interface gets and sets the popover element to control via an {{htmlelement("input")}} element of `type="button"`.
+
+It is the JavaScript equivalent of the [`popovertarget`](/en-US/docs/Web/HTML/Element/button#popovertarget) HTML attribute.
+
+## Value
+
+A reference to a popover element in the DOM.
+
+## Examples
+
+```js
+function supportsPopover() {
+ return HTMLElement.prototype.hasOwnProperty("popover");
+}
+
+const popover = document.getElementById("mypopover");
+const toggleBtn = document.getElementById("toggleBtn");
+
+const popoverSupported = supportsPopover();
+
+if (popoverSupported) {
+ popover.popover = "auto";
+ toggleBtn.popoverTargetElement = popover;
+ toggleBtn.popoverTargetAction = "toggle";
+} else {
+ console.log("Popover API not supported.");
+}
+```
+
+## Specifications
+
+{{Specifications}}
+
+## Browser compatibility
+
+{{Compat}}
+
+## See also
+
+- [Popover API](/en-US/docs/Web/API/Popover_API)
diff --git a/files/en-us/web/api/popover_api/index.md b/files/en-us/web/api/popover_api/index.md
new file mode 100644
index 000000000000000..13348b432e2311a
--- /dev/null
+++ b/files/en-us/web/api/popover_api/index.md
@@ -0,0 +1,98 @@
+---
+title: Popover API
+slug: Web/API/Popover_API
+page-type: web-api-overview
+status:
+ - experimental
+browser-compat: api.HTMLElement.popover
+---
+
+{{SeeCompatTable}}{{DefaultAPISidebar("Popover API")}}
+
+The **Popover API** provides developers with a standard, consistent, flexible mechanism for displaying popover content on top of other page content. Popover content can be controlled either declaratively using HTML attributes, or via JavaScript.
+
+## Concepts and usage
+
+A very common pattern on the web is to show content over the top of other content, drawing the user's attention to specific important information or actions that need to be taken. This content can take several different names — overlays, popups, popovers, dialogs, etc. We will refer to them as popovers through the documentation. Generally speaking, these can be:
+
+- **modal**, meaning that while a popover is being shown, the rest of the page is rendered non-interactive until the popover is actioned in some way (for example an important choice is made).
+- **non-modal**, meaning that the rest of the page can be interacted with while the popover is being shown.
+
+Popovers which are created using the popover API are always non-modal. If you want to create a modal popover, a {{htmlelement("dialog")}} element is the right way to go, although bear in mind that `