From 7363db084b83dce34262d1757a3f42f831a04739 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 6 Feb 2025 16:52:49 +0000 Subject: [PATCH 1/9] Document popover=hint --- files/en-us/web/api/htmlelement/index.md | 2 +- .../web/api/htmlelement/popover/index.md | 23 +++-- files/en-us/web/api/popover_api/index.md | 4 +- .../en-us/web/api/popover_api/using/index.md | 97 ++++++++++++++++++- .../html/global_attributes/popover/index.md | 20 +++- 5 files changed, 132 insertions(+), 14 deletions(-) diff --git a/files/en-us/web/api/htmlelement/index.md b/files/en-us/web/api/htmlelement/index.md index 8a6aa92ad23d0f8..aa9a5de0ea50fdb 100644 --- a/files/en-us/web/api/htmlelement/index.md +++ b/files/en-us/web/api/htmlelement/index.md @@ -73,7 +73,7 @@ _Also inherits properties from its parent, {{DOMxRef("Element")}}._ As a getter, it is the same as {{DOMxRef("HTMLElement.innerText")}} (it represents the rendered text content of an element and its descendants). As a setter, it replaces the selected node and its contents with the given value, converting any line breaks into {{HTMLElement("br")}} elements. - {{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. + - : Gets and sets an element's popover state via JavaScript (`"auto"`, `"hint"`, 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.spellcheck")}} - : A boolean value that controls the [spell-checking](/en-US/docs/Web/HTML/Global_attributes/spellcheck) hint. It is available on all HTML elements, though it doesn't affect all of them. - {{DOMxRef("HTMLElement.style")}} diff --git a/files/en-us/web/api/htmlelement/popover/index.md b/files/en-us/web/api/htmlelement/popover/index.md index 8513d9e457dba33..0e5eb1d8836aa42 100644 --- a/files/en-us/web/api/htmlelement/popover/index.md +++ b/files/en-us/web/api/htmlelement/popover/index.md @@ -8,7 +8,7 @@ browser-compat: api.HTMLElement.popover {{APIRef("Popover API")}} -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. +The **`popover`** property of the {{domxref("HTMLElement")}} interface gets and sets an element's popover state via JavaScript (`"auto"`, `"hint"`, 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. @@ -16,12 +16,21 @@ It reflects the value of the [`popover`](/en-US/docs/Web/HTML/Global_attributes/ 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. +- `"auto"` + + - : In [auto state](/en-US/docs/Web/API/Popover_API/Using#auto_state_and_light_dismiss): + - Popovers 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. + +- `"hint"` + + - : [`hint`](/en-US/docs/Web/API/Popover_API/Using#using_hint_popover_state) popovers are similar to `auto` popovers, but with a significant difference. They can be light-dismissed, but they do not light-dismiss `auto` popovers when shown, only `hint` popovers. `hint` popovers tend to be shown and hidden in response to non-click JavaScript events such as [`mouseover`](/en-US/docs/Web/API/Element/mouseover_event)/[`mouseout`](/en-US/docs/Web/API/Element/mouseout_event) and [`focus`](/en-US/docs/Web/API/Element/focus_event)/[`blur`](/en-US/docs/Web/API/Element/blur_event). When clicking on a button, the click itself would cause an open `auto` popover to light-dismiss. + +- `"manual"` + + - : In [manual state](/en-US/docs/Web/API/Popover_API/Using#using_manual_popover_state): + - Popovers cannot be "light dismissed", although declarative show/hide/toggle buttons will still work. + - Multiple independent popovers can be shown at a time. ## Examples diff --git a/files/en-us/web/api/popover_api/index.md b/files/en-us/web/api/popover_api/index.md index 8b47c00146188f9..5f417fe0583a9bd 100644 --- a/files/en-us/web/api/popover_api/index.md +++ b/files/en-us/web/api/popover_api/index.md @@ -41,7 +41,7 @@ See [Using the popover API](/en-US/docs/Web/API/Popover_API/Using) for a detaile ## 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. + - : A global attribute that turns an element into a popover element; takes a popover state (`"auto"`, `"hint"`, 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) @@ -64,7 +64,7 @@ See [Using the popover API](/en-US/docs/Web/API/Popover_API/Using) for a detaile ### 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. + - : Gets and sets an element's popover state via JavaScript (`"auto"`, `"hint"`, 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")}} diff --git a/files/en-us/web/api/popover_api/using/index.md b/files/en-us/web/api/popover_api/using/index.md index 6277d6e2202b8c5..7b02fbbcfdba8eb 100644 --- a/files/en-us/web/api/popover_api/using/index.md +++ b/files/en-us/web/api/popover_api/using/index.md @@ -65,7 +65,7 @@ You can see the behavior described above in action in our [Multiple auto popover ## Using manual popover state -The alternative to auto state is **manual state**, achieved by setting `popover="manual"` on your popover element: +One alternative to auto state is **manual state**, achieved by setting `popover="manual"` on your popover element: ```html
Popover content
@@ -190,6 +190,101 @@ There are three different ways to create nested popovers: 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. +## Using "hint" popover state + +There is a third type of popover you can create — **hint popovers**, designated by setting `popover="hint"` on your popover element. `hint` popovers are similar to `auto` popovers, but with a significant difference. They can be light-dismissed, but they do not light-dismiss `auto` popovers when shown, only `hint` popovers. + +This is useful for situations where, for example, you have toolbar buttons that can be pressed to show UI popovers, but you also want to reveal tooltips when the buttons are hovered, without dismissing the UI popovers. + +`hint` popovers tend to be shown and hidden in response to non-click JavaScript events such as [`mouseover`](/en-US/docs/Web/API/Element/mouseover_event)/[`mouseout`](/en-US/docs/Web/API/Element/mouseout_event) and [`focus`](/en-US/docs/Web/API/Element/focus_event)/[`blur`](/en-US/docs/Web/API/Element/blur_event). When clicking on a button, the click itself would cause an open `auto` popover to light-dismiss. + +See our [popover hint demo](https://mdn.github.io/dom-examples/popover-api/popover-hint/) ([source](https://github.com/mdn/dom-examples/tree/main/popover-api/popover-hint)) for an example that behaves exactly as described above. The demo features a button bar; when pressed, the buttons show popup sub-menus inside which further options can be selected. However, when hovered over or focused, the buttons also show tooltips to give the user an idea of what each button does. + +In the below sections, we'll walk through all the important parts of the code. + +### Creating the sub-menus with `popover="auto"` + +The popup sub-menus are created declaratively, using `auto` popovers. First, the control buttons: + +```html +
+ + + + + +
+``` + +Now, the popovers themselves: + +```html + + + +``` + +### Creating the tooltips with `popover="hint"` + +The sub-menu popovers work fine as they are, opening when the toolbar buttons are clicked, but how do we also show tooltips on button hover/focus? First, we create the tooltips in HTML, using `hint` popovers: + +```html +
Tooltip A
+
Tooltip B
+
Tooltip C
+``` + +To control the showing/hiding, we need to use JavaScript. First of all, we grab references to the `hint` popovers and the control buttons in two separate {{domxref("NodeList")}}s using {{domxref("Document.querySelectorAll()")}}: + +```js +const tooltips = document.querySelectorAll(".tooltip"); +const btns = document.querySelectorAll("#button-bar button"); +``` + +Next, we create a function, `addEventListeners()`, which sets four event listeners (via {{domxref("EventTarget.addEventListener()")}}) on a given {{htmlelement("button")}}, chosen by grabbing the ` @@ -63,6 +63,18 @@ Auto state is useful when you only want to show a single popover at once. Perhap 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. +## Popover accessibility features + +When a relationship is established between a popover and its control (invoker) via the `popovertarget` attribute, the API automatically makes two other changes to the environment to allow keyboard and assistive technology (AT) users to more easily interact with the popover: + +- When the popover is shown, the keyboard focus navigation order is updated so that the popover is next in the sequence: for example, when a button is pressed to show a popover, any buttons inside the popover will be next in the tabbing order (will be focused by pressing the Tab key). Conversely, when closing the popover via the keyboard (usually via via the Esc key), focus is shifted back to the invoker. +- To allow AT such as screen readers to make sense of the relationship between the invoker and the popover, an implicit [`aria-details`](/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-details) and [`aria-expanded`](/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-expanded) relationship is set up between them. + +Setting up a relationship between a popover and its control in this manner also creates an [Implicit popover anchor association](/en-US/docs/Web/API/Popover_API/Using#implicit_popover_anchor_associations). + +> [!NOTE] +> You can also set up a popover-invoker relationship using the `source` option of the {{domxref("HTMLElement.showPopover()")}} and {{domxref("HTMLElement.togglePopover()")}} methods, but bear in mind that in this case, only the focus navigation order changes are made, not the implicit ARIA relationship. This because the `source` option can be set to any kind of element, not just `