Description
https://html.spec.whatwg.org/multipage/popover.html
https://html.spec.whatwg.org/multipage/interactive-elements.html#the-dialog-element
https://html.spec.whatwg.org/multipage/interactive-elements.html#details-notification-task-steps
The show/hide steps for these happen on the same thread. However, a task is queued to fire the "close"
and "toggle"
events on dialog and popovers respectfully.
This creates a weird situation where the event could fire before or after the next render. Given that "I'm here now!" events are often used by developers as a time to enhance elements, this creates a race condition where the original state may be seen for a frame - a flash of unenhanced content. This would be really difficult to debug.
The solution in the <dialog>
/<details>
case would be to instead use a mutation observer for the open
attribute, since that's guaranteed to happen before rendering. With popover, I guess you could use the "beforetoggle"
event, but this event is also cancellable, so it isn't exactly "I'm here now!".
Option 1: Do nothing
Accept that it's a rotten bit of the platform, that will grow, since new features (like popover) will copy the behaviour in the name of consistency.
'select' events on various inputs also queue in this way.
Option 2: Dispatch the event synchronously
This is usually how events work when the action is performed on the main thread.
However, I think there's some reluctance to do this for <dialog>
and <details>
, since it's related to an attribute change, and for some reason we don't want to fire events in relation to DOM changes?
Also, changing from async to sync might be a compat risk for <dialog>
and <details>
.
Option 3: Dispatch the event in a microtask
This is how mutation observers work, which are related to DOM changes. It also allows for some debouncing, and it's still async.
Option 4: Dispatch the event in the render steps
This is how resize/scroll/pointer events work.
However, if the dialog is shown after this point in the render steps, you'd still get a flash of unenhanced content.
My preference is for option 2 or 3.
I can't decide if "input"
events behave this way. The HTML spec suggests it might, but the UI events spec says it must be dispatched immediately.