#1005: Dispatching Toggle Events for Dialog open/close

Visit on Github.

Opened Oct 17, 2024

こんにちは TAG-さん!

I'm requesting a TAG review of Dispatching Toggle Events for Dialog open/close.

It is useful for web authors do determine when their <dialog> elements open and close. popover already has ToggleEvent which is dispatched when a popover opens or closes, but <dialog> does not. The current way to detect when a <dialog> opens is to register a mutation observer to check for open, however, this is quite a lot of work where an event would be easier.

I propose we add dispatching of ToggleEvent for <dialog> also. To be explicit: when show or showModal is called, <dialog> should dispatch a ToggleEvent with newState=open. When a dialog is closed (via form or button or close signal) it should dispatch a ToggleEvent with newState=closed.

Further details:

  • I have reviewed the TAG's Web Platform Design Principles
  • Relevant time constraints or deadlines: Ideally in the next 2 weeks so we can continue to ship in Firefox.
  • The group where the work on this specification is currently being done: whatwg
  • The group where standardization of this work is intended to be done (if different from the current group): whatwg
  • Major unresolved issues with or opposition to this specification: None
  • This work is being funded by: GitHub

You should also know that...

I've enabled this in Firefox nightly targeting 133, it is currently flagged in Chromium, but I've raised an I2S (https://groups.google.com/a/chromium.org/g/blink-dev/c/PxluqSXWXD4/m/7q3qwklWAAAJ) and I'm aiming to ship in M132.

Discussions

Comment by @dandclark Oct 24, 2024 (See Github)

(Not a TAG opinion)

I'm curious -- after this, do you also plan to work on adding beforetoggle to <details> (which you'd noted as missing in https://github.com/whatwg/html/issues/9743), or do you know if anyone plans to pick that up? Once <dialog> has these events it seems like beforetoggle on <details> is the last remaining place where that developers might be surprised to find one of them missing.

In any case, dispatching beforetoggle/toggle for <dialog> looks like a nice step towards consistency and I'm glad to see it moving towards cross-browser adoption.

Comment by @keithamus Oct 25, 2024 (See Github)

Yes I’d be happy to also work on <details>.

Discussed Oct 28, 2024 (See Github)
<blockquote>

The two types ("before" and "on") of event seem very useful things to have.

Why is this "toggle" and not separate "open" and "close" events? The platform is not entirely consistent here, but these elements likely need distinct actions for the two cases. We can't see a reason for this being a single event type. (We'd like to see a path toward harmonization of events across the platform, but that's a larger project.)

We also agree with Dan about &lt;details> and the opportunity for future work. That's not in scope here, but we encourage you to look into it.

</blockquote>
Comment by @jyasskin Oct 29, 2024 (See Github)

We discussed this in a breakout today:

The two types ("before" and "on") of event seem like very useful things to have.

Why is this "toggle" and not separate "open" and "close" events? The platform is not entirely consistent here, but these elements likely need distinct actions for the two cases. We don't see why this should be a single event type. (We'd also like to see a path toward harmonization of events across the platform, but that's a larger project.)

We also agree with Dan about <details> and the opportunity for future work. That's not in scope here, but we encourage you to look into it.

Comment by @keithamus Oct 30, 2024 (See Github)

Having the separate event would likely lead to setting up 2 event listeners instead of one for some fairly common tasks, but I can see why it might be nicer for others.

The design was borrowed from popovers to keep symmetry, which perhaps themselves borrowed from the details toggle event (which doesn’t have the new/oldstate properties because it can be observed via the open attribute).

Comment by @jyasskin Oct 30, 2024 (See Github)

I think it would help to see the common cases where you'd need 2 event listeners with mostly the same code. It does make sense to align the 3 kinds of elements, but maybe that should be done by adding open and close to popover (which we should file against HTML and not just discuss in this issue).

Comment by @martinthomson Oct 30, 2024 (See Github)

My intuition and experience with using these suggests that opening and closing <details> and <dialog> has very different reactions in a lot of cases. I would expect to see "toggle" handlers that have if (e.newState) {} else {} at the top level. I can see commonality in "open"/"close" handlers, but that seems less common and it can be handled with el.onopen = handleToggle.bind(true); el.onclose = handleToggle.bind(false) or similar. Choosing requires an understanding of how it might be used in practice.

... or you could ship both, but that seems like a premature commitment to waste.

Comment by @josepharhar Oct 31, 2024 (See Github)

We could go back on beforetoggle/toggle and replace them with beforeopen/beforeclose/open/close, but this was decided quite a long time ago for popover in openui (and whatwg?), and would require a fairly large deprecation process since its shipped in all browsers now.

I'm not sure exactly where that discussion took place but I could find it if needed.

Discussed Nov 4, 2024 (See Github)

Jeffrey: two comments to choose from..

Matthew: both about consistency

Peter: two different things to be consistent with

Amy: what if we gave them both paths to consistency and handed the decision back

Peter: ask for a broader conversation among stakeholders

Jeffrey: they're likely to pick the one they've already gone with. We're only going to get a change for using open and close if we really push for it

Peter: push harder on the fact that we have established precedent with the open pseudoclass and property and that wasn't taken into consideration properly in the past and should be rethought

Matthew: any explainer about where they considered the alternatives and discussed it

Jeffrey: it's in the issue discussion: https://github.com/openui/open-ui/issues/607#issuecomment-1309330785.

Matthew: also discussion about how things might expand in future.. open and close might be all we need. Is there another aspect for which we could say this is likely to be better.

Peter: I can redraft to blend them

Jeffrey: the :open pseudoclass is newer than all of this. CSS can't do toggle there, they have to do open and close.

Peter: a resting state, not a transition.

New draft for the second option, from Slack:

<blockquote>

We want to emphasize the goal of consistency across the platform, between CSS properties, HTML attributes, and JS methods and events. Unfortunately, none of these are consistent in the current platform, so this change needs to instead chart a plausibly-consistent path forward.

Because <details> and <dialog> have open attributes, CSS added :open and :closed properties, and the event handlers seem likely to be more different than similar, we're inclined to think that the better path forward is to use "open" and "close" everywhere. That implies that it would be best for popover to also migrate from show/hide to open/close. (It doesn't imply that we should try to get rid of the various toggle*() methods.) We recognize that retrofitting new names onto shipped features is a big project, so it would be acceptable to just apply this pattern in the future, but if the community generally approves of this path, we'll file issues in HTML to suggest the retrofit.

</blockquote>
Discussed Nov 4, 2024 (See Github)

Jeffrey: I had a useful discussion with them this morning... About idea... The objection that it's more typing for authors came up....

Lea: is the idea that open and close would still exist? or phase it out?

Jeffrey: for elements that already have open/close it would stick around but for new things it would be toggle. New state.

Lea: I like this.

Tess: this feels like one of those cases where we are chasing API design fads... Ideally the web's API surface moves more slowly than trends in JavaScript libraries? When we hadd things to the web platform that doesn't look like the web but looks like popular JS libraries, then I would like to see some justification for that... There's no such things as adding web features in a vaccuum. My knee-jerk worry.

Jeffrey: It looks like the precedent that Domenic was following was the details element which has toggle....

Lea: besides what Jeffrey mentioned about details it seems that on the web platform we use a single event for state changes... So that seems to be on par... More than an open and close event...

Yves: as we already have open/close it's easy to have another state. In the case of a toggle it might be more difficult... Especially if you have 2 ways of doing the same thing... something about not doing the same thing 2 different ways in the design principles? There might be dragons.

Dan: https://www.w3.org/TR/design-principles/#consistency ?

discussion on toggle vs state change?

Peter: like a light switch - 2 positions.

Lea: state change is way to generic.

Jeffrey: things are open and closed - not much prospect to add another state... Following precednet - they were right to extend toggle to dialog.

Lea: What about popover?

Peter: uses toggle.

Jeffrey: the event is called toggle but the actions are show and hide.

Peter: having open / close events would be more consistent with CSS... Checkboxes... that pattern comes from other input elements that definitely have more than 2 states. In my mind having open/close event feels more proper. Having them as separate event handlers might be more convenient. Consistency is my main concern. Popover is the odd one out... Not sure that's the pattern to follow. At least "pick a lane and stick to it."

Jeffrey: writes proposal comment

Dan: noting positive review from Mozilla: https://github.com/mozilla/standards-positions/issues/1101

Peter: details has a boolean open attribute... I'd love us to be consistent between CSS, properties, and events... right now it's inconsistent.

Lea: a shared toggle event class? Then you could also do isevent instance of toggleevent...

Peter: a common base class named toggle is fine but more concerned with the event names... I think there's value to developers (DX) to get some consistency... Suggest we leave the comment and not close... but get feedback from the broader community...

satisfied with concerns:

<blockquote>

We want to emphasize the goal of consistency across the platform, between CSS properties, attributes, methods, and events. Unfortunately, none of these are consistent. Based on the history of details having a toggle event and dialog only having a close event, we think popover was correct to use toggle, and then this change is correct to extend that to dialog. There's an argument that open/close would be more consistent with the CSS :open and :closed selectors, but we think it's worth keeping consistency with the events.

</blockquote>

Or unsatisfied:

<blockquote>

We want to emphasize the goal of consistency across the platform, between CSS properties, attributes, methods, and events. Unfortunately, none of these are consistent. Because the elements have open attributes, and CSS added :open and :closed properties, we think the better path forward would be to use "open" and "close" everywhere, across event names and method names. This implies that it would be ideal to retrofit open and close events onto popover too, and we'll file an issue with HTML to ask to do that.

</blockquote>
Comment by @jyasskin Nov 4, 2024 (See Github)

@josepharhar I'd love to see the popover discussion that settled on toggle events instead of open/close. The TAG can be useful in identifying likely inconsistencies with either the rest of the platform or common developer needs, but if the domain experts have already examined the exact question we want to raise, I think we should usually accept their decision.

Comment by @keithamus Nov 4, 2024 (See Github)

FWIW it would not be as simple as open/close; you'd need beforeopen/beforeclose also.

This was discussed in 2021 as part of OpenUI (https://www.w3.org/2021/05/13-openui-minutes.html#t01) where Robert pointed out the precedent for event naming around before; (e.g. beforeinput or beforeunload). This meeting settled on beforeshow/beforehide. At some point this was tweaked to open/closed (though I can't find that thread).

So in 2022 https://github.com/whatwg/html/issues/8386 was raised which proposed the various beforeopen/afteropen/beforeclosed/afterclosed. Domenic asked why we need a set of events for this, and pointed out that toggle could be re-used for the after* events: https://github.com/whatwg/html/issues/8386#issuecomment-1306664435. Perhaps during a meeting it was resolved to also use beforetoggle; as the comment here suggests: https://github.com/whatwg/html/issues/8386#issuecomment-1432654221.

I'm sure @josepharhar could find more threads exposing this level of discussion but this is what I could find.

Comment by @jyasskin Nov 4, 2024 (See Github)

@keithamus Perfect, thanks! It looks like the idea of unifying the *open and *close events into a single event started in @mfreed7's https://github.com/openui/open-ui/issues/607#issuecomment-1309330785 in 2022, with Mason echoing the concern here that "It takes more work to write the event handler" (although the potential confusion is gone in the current event design with newState). @domenic endorsed the unification with "I think it will be less work for some use cases, e.g. event handlers that mainly want to sync the state change with some other part of the page and thus would have to listen to both events anyway." @domenic, do you still think moving from *open/*close to *toggle event was the right choice?

As a personal, non-TAG, opinion I think https://w3ctag.github.io/design-principles/#consistency indicates that dialog, details, and popover should have the same set of event names for this purpose, even if they're not the most ergonomic set for the most common uses. We could try to switch all three over to the open/close event set (for which we'd need to file an issue in HTML rather than here), if removing an if statement justifies that work. Someone from the TAG will reply again if we develop any group opinions.

Comment by @keithamus Nov 4, 2024 (See Github)

We could try to switch all three over to the open/close event set

Another consideration here is that while <dialog> and <details> use open/closed as part of their vernacular, popover uses show/hide. So does it make more sense to have <dialog> and <details> to using open/close events while popover has the asymmetrical show/hide events?

Discussed Nov 11, 2024 (See Github)

Peter to draft a comment.

Discussed Jan 6, 2025 (See Github)

https://github.com/w3ctag/meetings/blob/gh-pages/2024/telcons/11-04-minutes.md#dispatching-toggle-events-for-dialog-openclose---martinthomson-jyasskin-plinss: Peter was going to draft a comment.

OpenUI asked the same question in 2022 in https://github.com/openui/open-ui/issues/607#issuecomment-1309330785. They decided on toggle. Our biggest concern is consistency across the platform. So we should be filing issues to make toggle happen everywhere. If it turns out not to fit everywhere, that would be a sign that we need to go back and try to make open and close happen everywhere.

<blockquote> We understand that there was a long discussion that resulted in a single 'toggle' event rather than 'open'/'close' events, and don't want to unnecessarily reopen that discussion. However, the platform is currently inconsistent between CSS psuedo-classes, properties, attributes, methods, and events. We feel having platform consistency outweighs slight improvements over DX in specific cases here. If the path forward is a single 'toggle' event, then the CSS pseudo-classes, properties, attributes and methods should be made consistent with that pattern. For example, the pseudo-class values should match the ToggleEvent's `newState` values, which we believe they do. For properties, attributes, and methods, to what extent are they consistent with the 'toggle' pattern? If the toggle pattern doesn't fit well with the other uses, then it may be time to rethink 'toggle' vs 'open'/'close'. </blockquote>
Comment by @plinss Jan 7, 2025 (See Github)

We understand that there was a long discussion that resulted in a single 'toggle' event rather than 'open'/'close' events, and don't want to unnecessarily reopen that discussion. However, the platform is currently inconsistent between CSS pseudo-classes, properties, attributes, methods, and events. We feel having platform consistency outweighs slight improvements over DX in specific cases here. If the path forward is a single 'toggle' event, then the CSS pseudo-classes, properties, attributes and methods should be made consistent with that pattern. For example, the pseudo-class values should match the ToggleEvent's newState values, which we believe they do. For properties, attributes, and methods, to what extent are they consistent with the 'toggle' pattern? If the toggle pattern doesn't fit well with the other uses, then it may be time to rethink 'toggle' vs 'open'/'close'.

Comment by @keithamus Jan 8, 2025 (See Github)

For properties, attributes, and methods, to what extent are they consistent with the 'toggle' pattern?

They are indeed inconsistent.

  • <dialog> has show(), showModal() which will typically result in the dialog gaining an open attribute, and close() which will typically result in the dialog losing the open attribute. In CSS one can use dialog[open] to select for open dialogs, and dialog:modal for modal dialogs.

  • <details> does not have any methods to control this, one must instead set the open attribute, and use [open] in CSS.

  • popover elements have showPopover() and hidePopover() (as well as togglePopover()), but they do not have an attribute set on them during open, and instead must rely on :popover-open to check if they're open or not. Other than the methods (or user interaction) it's also possible to remove the popover attribute to close the popover.

Some directions we could go in to make them more consistent:

  • Ensuring <dialog> respects the addition/removal of the open attribute. This is being discussed in https://github.com/whatwg/html/pull/10124 but it has some issues around timings and has stalled.

  • Adding a universal :open pseudo class (and the complementary :closed class) to denote any element that transitioned into newState = 'open' (e.g. a <dialog> with showModal(), popover with showPopover() or <details open> element). This is being discussed in https://github.com/whatwg/html/issues/8625.

  • Adding a show() method to <details> which effectively adds the open attribute. I don't think this has been discussed before, but it is a possibility.

  • Having a declarative alternative for popovers similar to the open attribute for <dialog>/<details>. One thing we could do is make open an enumerated attribute - such that open=popover, open=details, open=modal are valid values. This has been discussed in https://github.com/whatwg/html/issues/10171.

  • Adding toggle() or toggleModal() to <dialog> elements for symmetry with popovers. We loosely discussed this idea in https://github.com/openui/open-ui/issues/954, but ultimately it wasn't deemed a priority.

Do you think the above suggestions for improvements would aid in DX?

Discussed Jan 13, 2025 (See Github)

we review response from Keith

Peter: i think this is a good enumeration of inconsistencies and proposals to fix them... We looked this last week that we're concerned with the inconsistency...

Lea: open event... on dialog.

Peter: keith talks about the open attribute...

Lea: I think harmonizing dialog and details is a good thing... Even if it's not perfect. And popovers as well... Harmonizing all of these would be a good thing...

Peter: my concern: is this going far enough... and also so many issues in different places.

Peter: but if even nothing else gets done, toggle is a step in the right direction.

Jeffrey: this toggle event is trying to make dialog match... events will be consistent across the platform with this change

Lea: popover is an attribute that can be added ... to anything ...

Jeffrey: there is an issue on HTML for doing that: https://github.com/whatwg/html/issues/10171.

Lea: open=details ... seems like a footgun? tends to create usability problems if you add noops like that.

Peter: i wonder about situations like where something is opened differently...

Lea: i don't think we need to figure that out in this issue.

Peter: I think all the rest of these that have issues are steps in the right direction... but we need to make sure they all stay related... Most are in WHATWG but some are in OpenUI... people considering each issue should be considering them as part of harmonizing... Willing to close this issue as satisfied...

Lea: close event ... should apply to all of these...

Peter: you're saying we should add close event to other things?

Lea: seems like it

Jeffrey: I'm worried about redundant events in the platforn... I'm worried about performance cost of firing extra events...

Lea: should we deprecate close then?

Jeffrey: ideally yet.

Peter: worried about the next thing...

Tess: we have "aim for consistency"...

Peter: one way forward is to let developers choose, other way forward is to pick one. I see both sides...

Dan: developer complexity

Tess: the obvious concern ... you have a web site maintained by more than one person... developers stepping on each others toes... and they have to figure out that there are 2 events firing... Not great.

Dan: +1

Jeffrey: we could give them the choice: either deprecate one of the events or add all of them everywhere.

Peter: have they even specified... and in what order?

Peter: I think Tess raises a valid point... it's important to specify what order you're firing them in... even if one of them is deprecated...

Jeffrey: it does specify that the toggle stuff happens before the close event...

Peter: bottom line?

Dan: what do we say along with the satisfied?

Peter: I think we should say .. do we deprecate the open/close or recommend they add open/close to everything?

<blockquote>

Thanks for listing all those issues. It looks like work is being done to start harmonizing these.

We're satisfied with this work. The directions you outlined look good.

Regarding your questions: we're concerned with adding multiple redundant events in the platform from a developer complexity and performance perspective. Furthermore, having some elements with both types of events raises another inconsistency, we recommend that either all elements get both event types or the open/close events become deprecated.

</blockquote>

We agree to close as satisfied with the above comment, Peter to post.

Comment by @plinss Jan 13, 2025 (See Github)

Thanks for listing all those issues. It looks like work is being done to start harmonizing these.

We're satisfied with this work. The directions you outlined look good.

Regarding your questions: we're concerned with adding multiple redundant events in the platform from a developer complexity and performance perspective. Furthermore, having some elements with both types of events raises another inconsistency, we recommend that either all elements get both event types or the open/close events become deprecated.