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

+ + +
``` -### 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

+ + +
+``` + +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

+ + +
+``` + +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 `` elements are not put in the {{glossary("top layer")}} by default — popovers are. There is significant overlap between the two — you might for example want to create a popover that persists, but control it using declarative HTML. You can even turn a `` element into a popover if you want to combine popover control and top level placement with dialog semantics. + +Typical use cases for the popover API include user-interactive elements like action menus, custom "toast" notifications, form element suggestions, content pickers, or teaching UI. + +You can create popovers in two different ways: + +- Declaratively, via a set of new HTML attributes. A simple popover with a toggle button can be created using the following code: + + ```html + +
Popover content
+ ``` + +- Via a JavaScript API. For example, {{domxref("HTMLElement.togglePopover()")}} can be used to toggle a popover between shown and hidden. + +There are also new events to react to a popover being toggled, and CSS features to aid in styling popovers. All the new features are listed below. + +See [Using the popover API](/en-US/docs/Web/API/Popover_API/Using) for a detailed guide to using this API. + +## HTML attributes + +- [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) + - : A global attribute that turns an element into a popover element; takes a popover state (`"auto"` or `"manual"`) as its value. +- [`popovertarget`](/en-US/docs/Web/HTML/Element/button#popovertarget) + - : Turns a {{htmlelement("button")}} or {{htmlelement("input")}} element into a popover control button; takes the ID of the popover element to control as its value. +- [`popovertargetaction`](/en-US/docs/Web/HTML/Element/button#popovertargetaction) + - : Specifies the the action to be performed (`"hide"`, `"show"`, or `"toggle"`) on the popover element being controlled by a control {{htmlelement("button")}} or {{htmlelement("input")}}. + +## CSS features + +- {{cssxref("::backdrop")}} + - : The `::backdrop` pseudo-element is a full-screen element placed directly behind popover elements, allowing effects to be added to the page content behind the popover(s) if desired (for example blurring it out). +- {{cssxref(":popover-open")}} + - : The `:popover-open` pseudo-class matches a popover element only when it is in the showing state — it can be used to style popover elements when they are showing. + +## Interfaces + +- {{domxref("ToggleEvent")}} + - : Represents an event notifying the user when a popover element's state toggles between showing and hidden. It is the event object for the {{domxref("HTMLElement.beforetoggle_event", "beforetoggle")}} and {{domxref("HTMLElement.toggle_event", "toggle")}} events, which fire on popovers when their state changes. + +## Extensions to other interfaces + +### Instance properties + +- {{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("HTMLButtonElement.popoverTargetElement")}} and {{domxref("HTMLInputElement.popoverTargetElement")}} + - : Gets and sets the popover element being controlled by the control button. The JavaScript equivalent of the [`popovertarget`](/en-US/docs/Web/HTML/Element/button#popovertarget) HTML attribute. +- {{domxref("HTMLButtonElement.popoverTargetAction")}} and {{domxref("HTMLInputElement.popoverTargetAction")}} + - : Gets and sets the action to be performed (`"hide"`, `"show"`, or `"toggle"`) on the popover element being controlled by the control button. Reflects the value of the [`popovertargetaction`](/en-US/docs/Web/HTML/Element/button#popovertargetaction) HTML attribute. + +### Instance methods + +- {{domxref("HTMLElement.hidePopover()")}} + - : Hides a popover element by removing it from the top layer and styling it with `display: none`. +- {{domxref("HTMLElement.showPopover()")}} + - : Shows a popover element by adding it to the top layer. +- {{domxref("HTMLElement.togglePopover()")}} + - : Toggles a popover element between the showing and hidden states. + +### Events + +- `HTMLElement` {{domxref("HTMLElement.beforetoggle_event", "beforetoggle")}} event + - : Fired just before a popover element's state changes between showing and hidden, or vice versa. +- `HTMLElement` {{domxref("HTMLElement.toggle_event", "toggle")}} event + - : Fired just after a popover element's state changes between showing and hidden, or vice versa. This event already existed to signal state changes on {{htmlelement("details")}} elements, and it seemed logical to extend it for popover elements. + +## Examples + +See our [Popover API examples landing page](https://mdn.github.io/dom-examples/popover-api/) to access the full collection of MDN popover examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md new file mode 100644 index 000000000000000..f36b83d414e98d9 --- /dev/null +++ b/files/en-us/web/api/popover_api/using/index.md @@ -0,0 +1,302 @@ +--- +title: Using the Popover API +slug: Web/API/Popover_API/Using +page-type: guide +status: + - experimental +--- + +{{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. This article provides a detailed guide to using all of its features. + +## Creating declarative popovers + +In its simplest form, a popover is created by adding the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute to the element that you want to contain your popover content. An `id` is also needed to associate the popover with its controls. + +```html +
Popover content
+``` + +> **Note:** Setting the `popover` attribute with no value is equivalent to setting `popover="auto"`. + +Adding this attribute causes the element to be hidden on page load by having {{cssxref("display", "display: none")}} set on it. To show/hide the popover, you need to add some control buttons. You can set a {{htmlelement("button")}} (or {{htmlelement("input")}} of `type="button"`) as a popover control button by giving it a [`popovertarget`](/en-US/docs/Web/HTML/Element/button#popovertarget) attribute, the value of which should be the ID of the popover to control: + +```html + +
Popover content
+``` + +The default behavior is for the button to be a toggle button — pressing it repeatedly will toggle the popover between showing and hidden. + +If you want to change that behavior, you can use the [`popovertargetaction`](/en-US/docs/Web/HTML/Element/button#popovertargetaction) attribute — this takes a value of `"hide"`, `"show"`, or `"toggle"`. For example, to create separate show and hide buttons, you could do this: + +```html + + +
Popover content
+``` + +You can see how the previous code snippet renders in our [Basic declarative popover example](https://mdn.github.io/dom-examples/popover-api/basic-declarative/) ([source](https://github.com/mdn/dom-examples/tree/main/popover-api/basic-declarative)). + +> **Note:** If the `popovertargetaction` attribute is omitted, `"toggle"` is the default action that will be performed by a control button. + +When a popover is shown, it has `display: none` removed from it and it is put into the {{glossary("top layer")}} so it will sit on top of all other page content. + +## auto state, and "light dismiss" + +When a popover element is set with `popover` or `popover="auto"` as shown above, it is said to have **auto state**. The two important behaviors to note about auto state are: + +- 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 the [Nested popovers](#nested_popovers) section for more details. + +> **Note:** `popover="auto"` popovers are also dismissed by successful {{domxref("HTMLDialogElement.showModal()")}} and {{domxref("Element.requestFullscreen()")}} calls on other elements in the document. Bear in mind however that calling these methods on a shown popover will result in failure because those behaviors don't make sense on an already-shown popover. You can however call them on an element with the `popover` attribute that isn't currently being shown. + +Auto state is useful when you only want to show a single popover at once. Perhaps you have multiple teaching UI messages that you want to show, but don't want the display to start getting cluttered and confusing, or perhaps you are showing status messages where the new status overrides any previous status. + +You can see the behavior described above in action in our [Multiple auto popovers example](https://mdn.github.io/dom-examples/popover-api/multiple-auto/) ([source](https://github.com/mdn/dom-examples/tree/main/popover-api/multiple-auto)). Try light dismissing the popovers after they are shown, and see what happens when you try to show both at the same time. + +## Using manual popover state + +The alternative to auto state is **manual state**, achieved by setting `popover="manual"` on your popover element: + +```html +
Popover content
+``` + +In this state: + +- The popover cannot be "light dismissed", although declarative show/hide/toggle buttons (as seen earlier) will still work. +- Multiple independent popovers can be shown at a time. + +You can see this behavior in action in our [Multiple manual popovers example](https://mdn.github.io/dom-examples/popover-api/multiple-manual/) ([source](https://github.com/mdn/dom-examples/tree/main/popover-api/multiple-manual)). + +## Showing popovers via JavaScript + +You can also control popovers using a JavaScript API. + +The {{domxref("HTMLElement.popover")}} property can be used to get or set the [`popover`](/en-US/docs/Web/HTML/Global_attributes/popover) attribute. This can be used to create a popover via JavaScript, and is also useful for feature detection. For example: + +```js +function supportsPopover() { + return HTMLElement.prototype.hasOwnProperty("popover"); +} +``` + +Similarly: + +- {{domxref("HTMLButtonElement.popoverTargetElement")}} and {{domxref("HTMLInputElement.popoverTargetElement")}} provide an equivalent to the [`popovertarget`](/en-US/docs/Web/HTML/Element/button#popovertarget) attribute, allowing you to set up the control button(s) for a popover, although the property value taken is a reference to the popover DOM element to control. +- {{domxref("HTMLButtonElement.popoverTargetAction")}} and {{domxref("HTMLInputElement.popoverTargetAction")}} provide an equivalent to the [`popovertargetaction`](/en-US/docs/Web/HTML/Element/button#popovertargetaction) global HTML attribute, allowing you to specify the action taken by a control button. + +Putting these three together, you can programmatically set up a popover and its control button, like so: + +```js +const popover = document.getElementById("mypopover"); +const toggleBtn = document.getElementById("toggleBtn"); + +const keyboardHelpPara = document.getElementById("keyboard-help-para"); + +const popoverSupported = supportsPopover(); + +if (popoverSupported) { + popover.popover = "auto"; + toggleBtn.popoverTargetElement = popover; + toggleBtn.popoverTargetAction = "toggle"; +} else { + toggleBtn.style.display = "none"; +} +``` + +You also have several methods to control showing and hiding: + +- {{domxref("HTMLElement.showPopover()")}} to show a popover. +- {{domxref("HTMLElement.hidePopover()")}} to hide a popover. +- {{domxref("HTMLElement.togglePopover()")}} to toggle a popover. + +For example, you might want to provide the ability to toggle a help popover on and off by clicking a button or pressing a particular key on the keyboard. The first one could be achieved declaratively, or you could do it using JavaScript as shown above. + +For the second one, you could create an event handler that programs two separate keys — one to open the popover and one to close it again: + +```js +document.addEventListener("keydown", (event) => { + if (event.key === "h") { + if (popover.matches(":popover-open")) { + popover.hidePopover(); + } + } + + if (event.key === "s") { + if (!popover.matches(":popover-open")) { + popover.showPopover(); + } + } +}); +``` + +This example uses {{domxref("Element.matches()")}} to programmatically check whether a popover is currently showing. The {{cssxref(":popover-open")}} pseudo-class matches only popovers that are currently being shown. This is important to avoid the errors that are thrown if you try to show an already-shown popover, or hide an already-hidden popover. + +Alternatively, you could program a single key to show _and_ hide the popover like this: + +```js +document.addEventListener("keydown", (event) => { + if (event.key === "h") { + popover.togglePopover(); + } +}); +``` + +See our [Toggle help UI example](https://mdn.github.io/dom-examples/popover-api/toggle-help-ui/) ([source](https://github.com/mdn/dom-examples/tree/main/popover-api/toggle-help-ui)) to see the popover JavaScript properties, feature detection, and `togglePopover()` method in action. + +## Dismissing popovers automatically via a timer + +Anoher common pattern in JavaScript is dismissing popovers automatically after a certain amount of time. You might for example want to create a system of "toast" notifications, where you have multiple actions underway at a time (for example multiple files uploading), and want to show a notification when each one succeeds or fails. For this you'll want to use manual popovers so you can show several at the same time, and use {{domxref("setTimeout")}} to remove them. A function for handling such popovers might look like so: + +```js +function makeToast(result) { + const popover = document.createElement("article"); + popover.popover = "manual"; + popover.classList.add("toast"); + popover.classList.add("newest"); + + let msg; + + if (result === "success") { + msg = "Action was successful!"; + popover.classList.add("success"); + successCount++; + } else if (result === "failure") { + msg = "Action failed!"; + popover.classList.add("failure"); + failCount++; + } else { + return; + } + + popover.textContent = msg; + document.body.appendChild(popover); + popover.showPopover(); + + updateCounter(); + + setTimeout(() => { + popover.hidePopover(); + popover.remove(); + }, 4000); +} +``` + +You can also use the {{domxref("HTMLElement.beforetoggle_event", "beforetoggle")}} event to perform a follow-up action when a popover shows or hides. In our example we execute a `moveToastsUp()` function to make the toasts all move up the screen to make way each time a new toast appears: + +```js +popover.addEventListener("toggle", (event) => { + if (event.newState === "open") { + moveToastsUp(); + } +}); + +function moveToastsUp() { + const toasts = document.querySelectorAll(".toast"); + + toasts.forEach((toast) => { + if (toast.classList.contains("newest")) { + toast.style.bottom = `5px`; + toast.classList.remove("newest"); + } else { + const prevValue = toast.style.bottom.replace("px", ""); + const newValue = parseInt(prevValue) + 50; + toast.style.bottom = `${newValue}px`; + } + }); +} +``` + +See our [Toast popover example](https://mdn.github.io/dom-examples/popover-api/toast-popovers/) ([source](https://github.com/mdn/dom-examples/tree/main/popover-api/toast-popovers)) to see the above example snippets in action, and full comments for explanation. + +## Nested popovers + +There is an exception to the rule about not displaying multiple auto popovers at once — when they are nested inside one another. In such cases, multiple popovers are allowed to both be open at the same time, due to their relationship with each other. This pattern is supported to enable use cases such as nested popover menus. + +There are three different ways to create nested popovers: + +1. Direct DOM descendants: + + ```html +
Parent +
Child
+
+ ``` + +2. Via invoking/control elements: + + ```html +
Parent + +
+ +
Child
+ ``` + +3. Via the `anchor` attribute: + + ```html +
Parent
+ +
Child
+ ``` + +See our [Nested popover menu example](https://mdn.github.io/dom-examples/popover-api/nested-popovers/) ([source](https://github.com/mdn/dom-examples/tree/main/popover-api/nested-popovers)) for an example. You'll notice that quite a few event handlers have been used to display and hide the subpopover appropriately during mouse and keyboard access, and also to hide both menus when an option is selected from either. Depending on how you handle loading of new content , either in an SPA or multi-page website, some of all of these may not be necessary, but they have been included in this demo for illustrative purposes. + +## Styling popovers + +The popover API has some related CSS features available that are worth looking at. + +In terms of styling the actual popover, you can select all popovers with a simple attribute selector (`[popover]`), or you select popovers that are showing using a new pseudo-class — {{cssxref(":popover-open")}}. + +When looking at the first couple of examples linked at the start of the article, you may have noticed that the popovers appear in the middle of the viewport. This is the default styling, achieved like this in the UA stylesheet: + +```css +[popover] { + position: fixed; + inset: 0; + width: fit-content; + height: fit-content; + margin: auto; + border: solid; + padding: 0.25em; + overflow: auto; + color: CanvasText; + background-color: Canvas; +} +``` + +To override the default styles and get the popover to appear somewhere else on your viewport, you would need to override the above styles with something like this: + +```css +:popover-open { + width: 200px; + height: 100px; + position: absolute; + inset: unset; + top: 5px; + right: 5px; + margin: 0; +} +``` + +You can see an isolated example of this in our [Popover positioning example](https://mdn.github.io/dom-examples/popover-api/popover-positioning/) ([source](https://github.com/mdn/dom-examples/tree/main/popover-api/popover-positioning)). + +The {{cssxref("::backdrop")}} pseudo-element is a full-screen element placed directly behind showing popover elements in the {{glossary("top layer")}}, allowing effects to be added to the page content behind the popover(s) if desired. You might for example want to blur out the content behind the popover to help focus the user's attention on it: + +```css +::backdrop { + backdrop-filter: blur(3px); +} +``` + +See our [Popover blur background example](https://mdn.github.io/dom-examples/popover-api/blur-background/) ([source](https://github.com/mdn/dom-examples/tree/main/popover-api/blur-background)) for an idea of how this renders. + +Finally, animation needs a special mention, as a lot of people are going to want to animate popovers between showing and hiding. As it stands, [a few updates to CSS behavior](https://open-ui.org/components/popover.research.explainer/#animation-of-popovers) are required to get popovers to be animatable, most notably enabling animation of elements as they move to and from `display: none`. We'll update this article as soon as animation is available for popovers. diff --git a/files/en-us/web/api/toggleevent/index.md b/files/en-us/web/api/toggleevent/index.md index 20be4cc122b29ea..c9afa9c901bb14e 100644 --- a/files/en-us/web/api/toggleevent/index.md +++ b/files/en-us/web/api/toggleevent/index.md @@ -9,10 +9,14 @@ browser-compat: api.ToggleEvent {{APIRef("UI Events")}}{{SeeCompatTable}} -The **`ToggleEvent`** interface represents an event notifying the user of an element whose state toggles between being open or closed. +The **`ToggleEvent`** interface represents an event notifying the user when a [popover element](/en-US/docs/Web/API/Popover_API)'s state toggles between showing and hidden. + +It is the event object for the `HTMLElement` {{domxref("HTMLElement.beforetoggle_event", "beforetoggle")}} and {{domxref("HTMLElement.toggle_event", "toggle")}} events, which fire on popovers when they transition between showing and hidden (before and after, respectively). {{InheritanceDiagram}} +> **Note:** `ToggleEvent` is unrelated to the `HTMLDetailsElement` {{domxref("HTMLDetailsElement.toggle_event", "toggle")}} event, which fires on a {{htmlelement("details")}} element when its `open`/`closed` state is toggled. Its event object is a generic {{domxref("Event")}}. + ## Constructor - {{DOMxRef("ToggleEvent.ToggleEvent", "ToggleEvent()")}} {{Experimental_Inline}} @@ -20,12 +24,30 @@ The **`ToggleEvent`** interface represents an event notifying the user of an ele ## Instance properties -_This interface inherits properties from its parents, {{DOMxRef("UIEvent")}} and {{DOMxRef("Event")}}._ +_This interface inherits properties from its parent, {{DOMxRef("Event")}}._ + +- {{DOMxRef("ToggleEvent.newState")}} {{ReadOnlyInline}} + - : A string (either `"open"` or `"closed"`), representing the state the element is transitioning to. +- {{DOMxRef("ToggleEvent.oldState")}} {{ReadOnlyInline}} + - : A string (either `"open"` or `"closed"`), representing the state the element is transitioning from. + +## Examples + +### Basic example + +```js +const popover = document.getElementById("mypopover"); + +// ... -- {{DOMxRef("ToggleEvent.oldState")}} {{ReadOnlyInline}} {{Experimental_Inline}} - - : Returns either `open` or `closed`, depending on which state the element is transitioning from. -- {{DOMxRef("ToggleEvent.newState")}} {{ReadOnlyInline}} {{Experimental_Inline}} - - : Returns either `open` or `closed`, depending on which state the element is transitioning to. +popover.addEventListener("beforetoggle", (event) => { + if (event.newState === "open") { + console.log("Popover is being shown"); + } else { + console.log("Popover is being hidden"); + } +}); +``` ## Specifications @@ -37,6 +59,6 @@ _This interface inherits properties from its parents, {{DOMxRef("UIEvent")}} and ## See also +- [Popover API](/en-US/docs/Web/API/Popover_API) - [`beforetoggle` event](/en-US/docs/Web/API/HTMLElement/beforetoggle_event) - [`toggle` event](/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/toggleevent/newstate/index.md b/files/en-us/web/api/toggleevent/newstate/index.md new file mode 100644 index 000000000000000..2606b9675a009c2 --- /dev/null +++ b/files/en-us/web/api/toggleevent/newstate/index.md @@ -0,0 +1,45 @@ +--- +title: "ToggleEvent: newState property" +short-title: newState +slug: Web/API/ToggleEvent/newState +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ToggleEvent.newState +--- + +{{APIRef("Popover API")}}{{SeeCompatTable}} + +The **`newState`** read-only property of the {{domxref("ToggleEvent")}} interface is a string representing the state the element is transitioning to. + +## Value + +A string. Possible values are `"open"` (the popover is being shown) or `"closed"` (the popover is being hidden). + +## Examples + +```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"); + } +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Popover API](/en-US/docs/Web/API/Popover_API) diff --git a/files/en-us/web/api/toggleevent/oldstate/index.md b/files/en-us/web/api/toggleevent/oldstate/index.md new file mode 100644 index 000000000000000..fa1a6a1f7f5e38e --- /dev/null +++ b/files/en-us/web/api/toggleevent/oldstate/index.md @@ -0,0 +1,45 @@ +--- +title: "ToggleEvent: oldState property" +short-title: oldState +slug: Web/API/ToggleEvent/oldState +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ToggleEvent.oldState +--- + +{{APIRef("Popover API")}}{{SeeCompatTable}} + +The **`oldState`** read-only property of the {{domxref("ToggleEvent")}} interface is a string representing the state the element is transitioning from. + +## Value + +A string. Possible values are `"open"` (the popover is going from showing to hidden) or `"closed"` (the popover going from hidden to shown). + +## Examples + +```js +const popover = document.getElementById("mypopover"); + +// ... + +popover.addEventListener("beforetoggle", (event) => { + if (event.oldState === "open") { + console.log("Popover is being hidden"); + } else { + console.log("Popover is being shown"); + } +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Popover API](/en-US/docs/Web/API/Popover_API) diff --git a/files/en-us/web/api/toggleevent/toggleevent/index.md b/files/en-us/web/api/toggleevent/toggleevent/index.md new file mode 100644 index 000000000000000..14178166b118887 --- /dev/null +++ b/files/en-us/web/api/toggleevent/toggleevent/index.md @@ -0,0 +1,62 @@ +--- +title: "ToggleEvent: ToggleEvent() constructor" +short-title: ToggleEvent() +slug: Web/API/ToggleEvent/ToggleEvent +page-type: web-api-constructor +status: + - experimental +browser-compat: api.ToggleEvent.ToggleEvent +--- + +{{APIRef("Popover API")}}{{SeeCompatTable}} + +The **`ToggleEvent()`** constructor creates a new {{domxref("ToggleEvent")}} object. + +## Syntax + +```js-nolint +new ToggleEvent(type, init) +``` + +### Parameters + +- `type` + - : A string representing the type of event. In the case of `ToggleEvent` this is always `toggleevent`. +- `init` + - : An object containing the following properties: + - `newState` + - : A string representing the state the element is transitioning to. Possible values are `"open"` and `"closed"`. + - `oldState` + - : A string representing the state the element is transitioning from. Possible values are `"open"` and `"closed"`. + +## Examples + +A developer would not use this constructor manually. A new `ToggleEvent` object is constructed when a handler is invoked as a result of a relevant event firing. + +For example: + +```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"); + } +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Popover API](/en-US/docs/Web/API/Popover_API) diff --git a/files/en-us/web/css/_colon_popover-open/index.md b/files/en-us/web/css/_colon_popover-open/index.md index b507c504274c00d..16a2edc60b38dfd 100644 --- a/files/en-us/web/css/_colon_popover-open/index.md +++ b/files/en-us/web/css/_colon_popover-open/index.md @@ -9,10 +9,7 @@ browser-compat: css.selectors.popover-open {{CSSRef}}{{SeeCompatTable}} -The **`:popover-open`** [CSS](/en-US/docs/Web/CSS) -[pseudo-class](/en-US/docs/Web/CSS/Pseudo-classes) represents an element with a -[`popover` attribute](/en-US/docs/Web/HTML/Global_attributes/popover) that is in -the open state. +The **`:popover-open`** [CSS](/en-US/docs/Web/CSS) [pseudo-class](/en-US/docs/Web/CSS/Pseudo-classes) represents a {{domxref("Popover API", "popover", "", "nocode")}} element (i.e. one with a [`popover` attribute](/en-US/docs/Web/HTML/Global_attributes/popover)) that is in the showing state. You can use this to apply style to popover elements only when they are shown. ## Syntax @@ -22,6 +19,39 @@ the open state. } ``` +## Examples + +By default, popovers appear in the middle of the viewport. The default styling is achieved like this in the UA stylesheet: + +```css +[popover] { + position: fixed; + inset: 0; + width: fit-content; + height: fit-content; + margin: auto; + border: solid; + padding: 0.25em; + overflow: auto; + color: CanvasText; + background-color: Canvas; +} +``` + +To override the default styles and get the popover to appear somewhere else on your viewport, you could need to override the above styles with something like this: + +```css +:popover-open { + width: 200px; + height: 100px; + position: absolute; + inset: unset; + top: 5px; + right: 5px; + margin: 0; +} +``` + ## Specifications {{Specifications}} @@ -29,3 +59,7 @@ the open state. ## Browser compatibility {{Compat}} + +## See also + +- [Popover API](/en-US/docs/Web/API/Popover_API) diff --git a/files/en-us/web/css/_doublecolon_backdrop/index.md b/files/en-us/web/css/_doublecolon_backdrop/index.md index 70e30eedaf903a1..a30ae4e9c983c0a 100644 --- a/files/en-us/web/css/_doublecolon_backdrop/index.md +++ b/files/en-us/web/css/_doublecolon_backdrop/index.md @@ -7,9 +7,13 @@ browser-compat: css.selectors.backdrop {{CSSRef}} -The **`::backdrop`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) is a box the size of the {{Glossary("viewport")}} which is rendered immediately beneath any element being presented in fullscreen mode. This includes both elements which have been placed in fullscreen mode using the [Fullscreen API](/en-US/docs/Web/API/Fullscreen_API) and {{HTMLElement("dialog")}} elements. +The **`::backdrop`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) is a box the size of the {{Glossary("viewport")}}, which is rendered immediately beneath any element being presented in the {{glossary("top layer")}}. This includes: -When multiple elements have been placed into fullscreen mode, the backdrop is drawn immediately beneath the frontmost such element, and on top of the older fullscreen elements. +- Elements which have been placed in fullscreen mode using the [Fullscreen API](/en-US/docs/Web/API/Fullscreen_API) {{domxref("Element.requestFullscreen()")}} method. +- {{HTMLElement("dialog")}} elements that have been shown in the top layer via a {{domxref("HTMLDialogElement.showModal()")}} call. +- {{domxref("Popover API", "Popover", "", "nocode")}} elements that have been shown in the top layer via a {{domxref("HTMLElement.showPopover()")}} call. + +When multiple elements have been placed into the top layer, each one has its own `::backdrop` pseudo-element. ```css /* Backdrop is only displayed when dialog is opened with dialog.showModal() */ @@ -18,7 +22,7 @@ dialog::backdrop { } ``` -All fullscreen elements are placed in a last-in/first out (LIFO) stack in the top layer, which is a special layer in the viewport which is always rendered last (and therefore on top) before drawing the viewport's contents to the screen. The `::backdrop` pseudo-element makes it possible to obscure, style, or completely hide everything located below the element when it's the topmost one in the top layer. +Elements are placed in a last-in/first out (LIFO) stack in the top layer. The `::backdrop` pseudo-element makes it possible to obscure, style, or completely hide everything located below a top layer element. `::backdrop` neither inherits from nor is inherited by any other elements. No restrictions are made on what properties apply to this pseudo-element. @@ -61,3 +65,4 @@ The resulting screen looks like this: - {{cssxref(":fullscreen")}} pseudo-class - {{HTMLElement("dialog")}} HTML element - [Fullscreen API](/en-US/docs/Web/API/Fullscreen_API) +- [Popover API](/en-US/docs/Web/API/Popover_API) diff --git a/files/en-us/web/html/element/button/index.md b/files/en-us/web/html/element/button/index.md index ae3a5273a9a0259..e4d272293ae5821 100644 --- a/files/en-us/web/html/element/button/index.md +++ b/files/en-us/web/html/element/button/index.md @@ -71,6 +71,20 @@ This element's attributes include the [global attributes](/en-US/docs/Web/HTML/G - `name` - : The name of the button, submitted as a pair with the button's `value` as part of the form data, when that button is used to submit the form. + +- `popovertarget` + - : Turns a `