New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add light dismiss functionality to <dialog>
#9373
Comments
I think this is what I'd expect to happen anyway, so that's good. |
Can you expand on this? Intuitively, there's definitely a concept of nesting, e.g. a dialog opened because of an action taken inside another open dialog. I guess popover's notion of nesting is different than this, and that's how you're using the term "nesting"?
I agree this result does seem reasonable. |
Supporting light dismiss for |
Sure. Dialogs can certainly be "stacked" like this, but different from Popover, there's no concept of "nested" popovers. The difference is mainly that Popover has complicated rules about how they're related. In the case of dialog, one dialog can open another dialog, but we don't have logic to connect them to each other. But I think that's ok: dialogs usually aren't used in a "nested" fashion, and when they are, the second dialog should be considered a standalone modal dialog. So one dialog should be dismissed at a time. Example: dialog 1 is "Do you want to save this file?", and on a "no" click, a second dialog shows "Are you sure??" which might cover dialog 1. Clicking outside should just light dismiss the topmost one, and leave the original modal visible.
I'm guessing that's very non-web-compatible. Since the existing dialog requires an explicit close, I bet there are dialogs that don't want to be light dismissed. A light dismiss dialog might not even be the majority use case for modal dialogs: I could see several types of modal dialog that really want explicit action. Like "Choose A or B" - cancel is not an option. |
agreed. light dismiss for modal dialogs should be an opt in, not a default, |
+100 we need this feature. And combined with #3567 I think this will solve a lot of the issues right now with |
One comment that came up in discussion was that the light dismiss behavior should differ from Popover in one respect: if the user clicks outside the dialog to light-dismiss it, that click should not "fall through" to the element underneath the backdrop. That might come for free depending on how we spec/implement this, and how it interacts with |
See openui/open-ui#834 for a quick summary of the TPAC discussion just now, and a new question to discuss the name of the attribute. |
Apologies if this is mentioned in the TPAC discussion or elsewhere that I've missed but I was under the impression the new proposed |
This is automatic for all "close requests", either popup or dialog or In today's TPAC discussion, we called the Esc key behavior "heavy dismiss" (which all dialogs have), to contrast it with the clicking-outside behavior "light dismiss" (which only Note that the HTML spec that got merged is a bit confused about this. https://html.spec.whatwg.org/#popover-light-dismiss lists the Esc key behavior under "canceling popovers"; that triggers "hide popover", not "light dismiss open popovers", which is correct. But the Note says that Esc is a subset of light dismiss, and the "canceling popovers" behavior is under the "Popover light dismiss" heading, so the non-normative aspects are confusing. I will add a fix to that to #9462, to make it clear that they are separate. |
Ah yeah that makes sense. I guess in that case my question should be. Should that behaviour be matched by this lightdismiss definition. If you have multiple dialogs opened without user activation should their light dismiss group such that when the ::backdrop is clicked they all close? It might be odd if escape or back swipe closes them all but you have to manually click out of all of them? |
Made a demo page with a "polyfill" https://demo.lukewarlow.dev/lightdismiss/ |
In the poll, many web developers are suggesting enumerated variants like At first I thought this was not a good idea, because we wanted dialogs to have a baseline close trigger of a close request. So the idea was just to add something that says "also give me close-when-clicking-on-backdrop". For which a boolean attribute name was most helpful. However, in https://bugs.chromium.org/p/chromium/issues/detail?id=1504283 I found out that there are developers using So now I think a model something like the following might work?
I'm not 100% satisfied with this API design, because (Regarding naming: as stated before, I think the name needs to include |
I would want to avoid click in the name because it ties it to a specific input type. I also would want to avoid closeon because it's too similar to onclose. How about closes=""? Then can do closes="closerequest backdrop" closetrigger(s) I think is also fine. While the empty list might be confusing I think it's probably fine (compared to any alternativs I can think of)? |
I agree with @lukewarlow on avoiding I think |
closers is quite nice and short. |
I think an explicit
I will say I'd estimate the order of popularity of these would be:
Having the most desirable be the most boilerplate is not the best. |
Agree re |
I'm not sure about
same with this:
Generally, as I mentioned here, I really don't want to start adding other ways to close the dialog. We spent considerable time ruling out "dismiss-on-scroll" or "dismiss-on-blur", so I'd hope we don't add those as values. They will be easy footguns for most people. For the same avoidance-of-footguns reason, I don't see any use case for a dialog that closes when you click/tap outside it, but does not close when you hit ESC. So there really are just three values/cases, right?
How about:
|
Has |
Interesting point. I agree backdrop is technically not correct in this way. I still think it might be a reasonable way for developers to think about it, because in the default case clicking outside = clicking the backdrop. But if you think it's too misleading, let's go with
This is a good point, and is probably right. However I've already been surprised once by learning that developers sometimes want dialogs that don't respond to close requests. So if anyone disagrees, or can find a dialog of this sort in the web or native platforms, that'd be very helpful info!
LGTM. (And avoids us having to choose between The following possible tweaks come to mind, but I think I prefer your proposal as-is. I just want to write them down in case others have strong feelings.
|
Am I correct in thinking that escape doesn't actually close a non-modal (non-popover) dialog currently. Is that gonna impact on the serialising of the default? |
Should closetrigger allow you to control popovers too? Manual popovers require JS currently but that might be heavy handed if you just wanted close request but not click outside? Don't want to over complicate things though. |
I'm inclined to agree with you that (2) seems to be the most natural. It keeps the existing behavior for non-modal dialogs unless
Here, I think the behavior is pretty clear. If the dialog is open as a dialog, |
There is precedent; in fact there are three separate types of precedent 😢. 1A: have the states be { none, closerequest, any, auto }, with an invalid value default and missing value default of auto, but no actual keyword for triggering the auto behavior. (The keywords are just { none, closerequest, any }.) Do the reflection "limited to only known values". In this version, whenever you are in the auto state (including when 1B: similar to 1A, but also declare the IDL attribute as nullable. Then instead of the empty string when in the auto state, you get 2: The other would be to have the states and keywords both match, as { none, closerequest, any }, and then do custom reflection. This reflection would allow I think 1A is probably better than 1B because we reserve 1B for cases where the empty string is valid ( Between 1A and 2, I lean toward 1A. Although it's kind of nice that in 2 you get some insight into the "actual" close triggers, it's a bit strange how it causes I recall @annevk having stronger opinions on this, so I'd like his take. |
Thanks for the thorough description of the options!
Any of the options sound ok to me, but 1A does sound the best overall. Option 2 sounds somewhat odd, and the developer can already check |
Is this something that would be ready for a spec patch or is more discussion needed on the exact specifics? It seems like there's agreement for option 1A right? |
Agenda+ to discuss this. It sounds like consensus is forming around this:
with reflection behavior as described in "1A" from #9373 (comment). The naming data comes from openui/open-ui#960 which has 46% of the vote for |
Something that would be good to get clarity on, if a dialog is showModal()ed with closedby="none" and then it's updated to closerequest or any does that then establish a close watcher or would it have to wait until closing and reshowing modally? Likewise if the dialog is showModal()ed with closedby of closerequest or any (or auto) and then changed to closedby="none" what happens to the existing close watcher that was established? Is it effectively destroyed? |
In my opinion, any changes in the value of the |
I agree fwiw, but might be slightly tricky as it will be in the wrong place in the stack potentially. And if you opened the modal with user activation but then switch closedby to create a close watcher after the fact that won't neccesarily have the useractivation you need and again lead to weird behaviours. Edge casey probably but just worth thinking about the specifics. |
Right - we need to figure out how to implement that. But from a developer point of view, it should "just work". Implementation-wise, we should have access to the guts of the close watcher stack, so this should at least be possible, if perhaps ugly. @domenic would know more. |
Changing popover attribute results in the popover being hidden. That's one possible solution here? Would be simpler to spec and implement that's for sure. |
Ooh, this is tricky. I think going back and inserting things into the close watcher stack after creation will be very difficult or impossible. So you'd probably need to have some sort of phantom close watcher that always gets placed there. One sketch might be that all close watchers get an "active" boolean. We then modify various parts of the spec to account for it. E.g. we skip non-active close watchers when issuing a close request, or counting the number of current groups for anti-abuse purposes, or similar. |
I think a phantom watcher could work, the reason I avoided it initially was because I think you can get in a state where rather than being wrong because it's on top of the stack but behind others. I guess to truly know we'd need to give it a go at speccing it and see what could end up being odd. |
As a follow up from todays whatnot I've raised standards positions for WebKit and Mozilla. I'm assuming I can count this as having interest from Chromium given @mfreed7 raised the issue? |
Chromium is officially supportive. 😊 |
As I mentioned in Mozilla's s-p, it would be good to think whether the features would apply to other cases too, not only . Like, would it make sense to have the same attribute working with popover? And if so, does that affect the API shape? |
Popover already has the behaviour, kind of. |
Right, I agree with this comment. I think this type of behavior is very API-specific, and the target is very specifically dialogs. Popover already has this behavior in a different form, and I haven't heard any requests for this type of feature on other elements/APIs. So I'd love to scope this to dialogs if possible. |
While I agree this shouldn't apply to popover, I wonder about whether it could apply to future high-level elements built on popover. If anyone has a list of those, doing some analysis would be helpful. E.g.: toast? Not sure what their default closedby would be, or whether it'd be reasonable to allow all three options... But even if we wanted to allow only 2 options, that would work fine with this design. |
The two concrete high level elements (obviously modulo name bikeshedding) I've heard discussed are:
In my head at least, both use the Popover API under the covers, and have an implicit |
This I think is key, if we have a specific element built on top of popover and it makes sense to allow two different variants different enough, then they probably should be two separate elements. Of course the same argument could be made for Dialog so maybe I'm wrong. But dialog is closer to popover than some |
One of the nice features of the Popover API is its light dismiss behavior. In several of the demos of Popover that I've seen, developers are doing something like this:
Using
<dialog>
with a popover attribute is perfectly fine semantically here, since the content represents a dialog. However, this pattern is being used almost entirely because of the features provided by the Popover API which are missing from the<dialog>
element itself. Note the usage of::backdrop
to obscure the backdrop entirely. That indicates that this really is meant to be a modal dialog, because the intent is to focus attention only on the dialog and keep the user from "seeing" the rest of the page. However, popovers aren't modal and as such they don'tinert
the rest of the page. So in the above example, keyboard users are free to tab-navigate to other content they can't see. Mouse users are free to click "through" the opaque background onto unseen elements. Generally, it'd be better if this was a plain old modal<dialog>
and not a popover.To get around this usage pattern, let's bring the missing functionality to
<dialog>
. #3567 discusses one of those behaviors, namely declarative invocation of<dialog>
. In this issue, I'd like to propose a mechanism to add light dismiss to<dialog>
s.Proposal (subject to bikeshedding):
With the
lightdismiss
attribute present, clicking outside the dialog, or hitting ESC (or other close signals) will have the same affect as callingdialog.close()
.Note one nuance, which is different from popover: since there's no concept of "nested" dialogs, if more than one dialog is open at a time, only the topmost (most recently opened) dialog will be closed on each light dismiss action. So if three dialogs are open and the user clicks outside all three of them, only the topmost dialog will close. Generally, nested dialogs is an anti-pattern, but even so, this feels the most natural to me anyway.
The text was updated successfully, but these errors were encountered: