Skip to content

Commit 303832e

Browse files
Editorial review: Document the ToggleEvent.source property (mdn#40533)
* Document the ToggleEvent.source property * Code review fixes * Fixes for hamishwillee review comments * Apply suggestions from code review * Update files/en-us/web/api/popover_api/using/index.md Co-authored-by: Hamish Willee <hamishwillee@gmail.com> --------- Co-authored-by: Hamish Willee <hamishwillee@gmail.com>
1 parent 32bfbcb commit 303832e

File tree

3 files changed

+154
-2
lines changed

3 files changed

+154
-2
lines changed

files/en-us/web/api/popover_api/using/index.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,20 @@ You can see how the previous code snippet renders in our [Basic declarative popo
4747
4848
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.
4949

50+
### `command` and `commandfor`
51+
52+
The [`commandfor`](/en-US/docs/Web/HTML/Reference/Elements/button#commandfor) and [`command`](/en-US/docs/Web/HTML/Reference/Elements/button#command) attributes provide very similar functionality to `popovertarget` and `popovertargetaction`, but with a more general design aimed at providing other functionality beyond popover commands, including custom commands.
53+
54+
The previous code snippet could be rewritten like this:
55+
56+
```html live-sample___command-commandfor
57+
<button commandfor="mypopover" command="show-popover">Show popover</button>
58+
<button commandfor="mypopover" command="hide-popover">Hide popover</button>
59+
<div id="mypopover" popover>Popover content</div>
60+
```
61+
62+
{{EmbedLiveSample("command-commandfor", "100%", "100")}}
63+
5064
## auto state, and "light dismiss"
5165

5266
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:
@@ -93,6 +107,30 @@ In this state:
93107

94108
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)).
95109

110+
## The `beforetoggle` and `toggle` events
111+
112+
You can respond to a popover being shown or hidden using the [`beforetoggle`](/en-US/docs/Web/API/HTMLElement/beforetoggle_event) and [`toggle`](/en-US/docs/Web/API/HTMLElement/toggle_event) events:
113+
114+
- `beforetoggle` is fired just before a popover is shown or hidden. This can be used for example to prevent the popover being shown or hidden (using {{domxref("Event.preventDefault()")}}), to add animation classes to a popover to animate it, or to cleanup the state of a popover after it has been used.
115+
- `toggle` is fired just after a popover is shown or hidden. This is generally used to run other code in response to a popover toggle state changing.
116+
117+
Both of these events have a {{domxref("ToggleEvent")}} event object. This event has the following features in addition to those inherited from the default {{domxref("Event")}} object:
118+
119+
- The {{domxref("ToggleEvent.oldState", "oldState")}} and {{domxref("ToggleEvent.newState", "newState")}} properties indicate which state the popover has just transitioned from and to, allowing you to respond specifically to a popover opening or closing.
120+
- The {{domxref("ToggleEvent.source", "source")}} property contains a reference to the HTML popover control element that initiated the toggle, allowing you to run different code in response to the toggle event depending on which control initiated it.
121+
122+
Typical usage might look something like this:
123+
124+
```js
125+
const popover = document.getElementById("mypopover");
126+
127+
popover.addEventListener("toggle", (e) => {
128+
console.log(e.newState);
129+
});
130+
```
131+
132+
See the previous reference links for more information and examples.
133+
96134
## Showing popovers via JavaScript
97135

98136
You can also control popovers using a JavaScript API.

files/en-us/web/api/toggleevent/index.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ The **`ToggleEvent`** interface represents an event notifying the user an Elemen
1111

1212
This is the event object for the `HTMLElement` {{domxref("HTMLElement.beforetoggle_event", "beforetoggle")}} and {{domxref("HTMLElement.toggle_event", "toggle")}} events, which fire on some elements just before and just after they transition between showing and hidden, respectively.
1313

14-
- `beforetoggle` fires on [popovers](/en-US/docs/Web/API/Popover_API) and {{htmlelement("dialog")}} elements
15-
- `toggle` fires on [popovers](/en-US/docs/Web/API/Popover_API), {{htmlelement("dialog")}} elements, and {{htmlelement("details")}} elements
14+
- `beforetoggle` fires on [popovers](/en-US/docs/Web/API/Popover_API) and {{htmlelement("dialog")}} elements.
15+
- `toggle` fires on [popovers](/en-US/docs/Web/API/Popover_API), {{htmlelement("dialog")}} elements, and {{htmlelement("details")}} elements.
1616

1717
{{InheritanceDiagram}}
1818

@@ -29,6 +29,8 @@ _This interface inherits properties from its parent, {{DOMxRef("Event")}}._
2929
- : A string (either `"open"` or `"closed"`), representing the state the element is transitioning to.
3030
- {{DOMxRef("ToggleEvent.oldState")}} {{ReadOnlyInline}}
3131
- : A string (either `"open"` or `"closed"`), representing the state the element is transitioning from.
32+
- {{DOMxRef("ToggleEvent.source")}} {{Experimental_Inline}} {{ReadOnlyInline}}
33+
- : An {{domxref("Element")}} object instance representing the HTML control that initiated the toggle.
3234

3335
## Examples
3436

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
---
2+
title: "ToggleEvent: source property"
3+
short-title: source
4+
slug: Web/API/ToggleEvent/source
5+
page-type: web-api-instance-property
6+
browser-compat: api.ToggleEvent.source
7+
---
8+
9+
{{APIRef("Popover API")}}
10+
11+
The **`source`** read-only property of the {{domxref("ToggleEvent")}} interface is an {{domxref("Element")}} object instance representing the HTML popover control element that initiated the toggle.
12+
13+
## Value
14+
15+
An {{domxref("Element")}} object instance, or `null` if the popover was not activated by a control element.
16+
17+
## Description
18+
19+
A {{htmlelement("button")}} element can be set as a popover control by specifying the [`id`](/en-US/docs/Web/HTML/Reference/Global_attributes/id) of the popover element in its [`commandfor`](/en-US/docs/Web/HTML/Reference/Elements/button#commandfor) or [`popovertarget`](/en-US/docs/Web/HTML/Reference/Elements/button#popovertarget) attribute (if the button is specified using `<input type="button">`, only the `popovertarget` attribute works).
20+
21+
When the [`toggle`](/en-US/docs/Web/API/HTMLElement/toggle_event) event fires on the popover, the `ToggleEvent` event object's `source` property will then contain a reference to the popover control button that initiated the toggle. This is useful for running different code in response to the `toggle` event depending on which control initiated it (see an [example](#basic_source_usage)).
22+
23+
Before the `source` property was available, developers would have to reimplement the `command` attribute functionality from scratch to provide a similar identifier and then monitor it with JavaScript to know which button invoked the popover.
24+
In addition, there was a danger of such JavaScript tasks blocking the showing or hiding of the popover.
25+
The `toggle` event is asynchronous, and therefore avoids this problem.
26+
27+
If the popover was not activated by a control button — for example, if the popover is being controlled using a JavaScript method such as {{domxref("HTMLElement.togglePopover()")}} — the `source` property returns `null`.
28+
29+
## Examples
30+
31+
### Basic `source` usage
32+
33+
This demo shows how to use the `source` property to perform a different action depending on which control button was used to close a popover.
34+
35+
#### HTML
36+
37+
Our markup contains a `<button>`, a {{htmlelement("p")}}, and a {{htmlelement("div")}} element. The `<div>` is designated as an [`auto` popover](/en-US/docs/Web/API/Popover_API/Using#auto_state_and_light_dismiss), and the button is designated as a control for showing the popover using the [`commandfor`](/en-US/docs/Web/HTML/Reference/Elements/button#commandfor) and [`command`](/en-US/docs/Web/HTML/Reference/Elements/button#command) attributes.
38+
39+
The popover contains a heading asking the user if they would like a cookie, and two buttons allowing them to select an answer of "yes" or "no". Each one of these buttons is designated as a control for hiding the popover.
40+
41+
```html live-sample___toggleevent-source
42+
<button commandfor="popover" command="show-popover">
43+
Select cookie preference
44+
</button>
45+
<p id="output"></p>
46+
<div id="popover" popover="auto">
47+
<h3>Would you like a cookie?</h3>
48+
<button id="yes" commandfor="popover" command="hide-popover">Yes</button>
49+
<button id="no" commandfor="popover" command="hide-popover">No</button>
50+
</div>
51+
```
52+
53+
```css hidden live-sample___toggleevent-source
54+
html {
55+
font-family: sans-serif;
56+
}
57+
58+
[popover] {
59+
border: 1px solid grey;
60+
padding: 10px 20px;
61+
border-radius: 5px;
62+
}
63+
64+
[popover] h3 {
65+
margin: 0 0 10px;
66+
}
67+
```
68+
69+
#### JavaScript
70+
71+
In our script, we start off by grabbing references to the "yes" and "no" buttons, the popover, and the output `<p>`.
72+
73+
```js live-sample___toggleevent-source
74+
const yesBtn = document.getElementById("yes");
75+
const noBtn = document.getElementById("no");
76+
const popover = document.getElementById("popover");
77+
const output = document.getElementById("output");
78+
```
79+
80+
We then add some feature detection to detect whether the HTML `command` attribute is supported, and whether the `source` property is supported. If either are not supported, we output an appropriate message to the output `<p>`. If both are supported, we add a [`toggle`](/en-US/docs/Web/API/HTMLElement/toggle_event) event listener to the popover. When fired, it checks if the "yes" or the "no" button was used to toggle (hide) the popover; an appropriate message is printed to the output `<p>` in each case.
81+
82+
```js live-sample___toggleevent-source
83+
if (yesBtn.command === undefined) {
84+
output.textContent = "Popover control command attribute not supported.";
85+
} else {
86+
popover.addEventListener("toggle", (event) => {
87+
if (event.source === undefined) {
88+
output.textContent = "ToggleEvent.source not supported.";
89+
} else if (event.source === yesBtn) {
90+
output.textContent = "Cookie set!";
91+
} else if (event.source === noBtn) {
92+
output.textContent = "No cookie set.";
93+
}
94+
});
95+
}
96+
```
97+
98+
#### Result
99+
100+
{{embedlivesample("toggleevent-source", "100%", "100")}}
101+
102+
## Specifications
103+
104+
{{Specifications}}
105+
106+
## Browser compatibility
107+
108+
{{Compat}}
109+
110+
## See also
111+
112+
- [Popover API](/en-US/docs/Web/API/Popover_API)

0 commit comments

Comments
 (0)