Closed domenic closed 10 months ago
Isn't consuming Esc
potentially dangerous on desktop too? E.g., when <dialog>
is used in combination with the fullscreen API?
It turns out no, since all browsers prioritize leaving fullscreen before any dialog processing. This is now specced rigorously, and I suppose it's possible we could even web platform test it.
On the surface, I'd think this is mainly a problem of a specific "back gesture". The reason for that is because "back gesture" on Android (and possibly other devices) is "global" and thus abuse of it is bad. The same would be the case in a hypothetical case of a TV-like remote with a back button - abusing that global button would be bad. Not sure how to express this in the CloseWatcher
API though. Really the only obvious solution I'd see is if a browser were to mediate the vetoable "cancel" signal, just as we do today in the onbeforeunload
with the system prompt. It's a bad UX, but clean abuse protection. Maybe there could be a compromise and a browser could prompt on a repeated "cancel" event?
To restate what I think @dvoytenko is saying, we have a fundamental conflict between encouraging platform-agnostic code, vs. desktop compat. I.e., if we preserve behavior on desktop by not limiting Esc, then desktop and Android will behave observably differently.
One way around this would potentially be to have desktop and Android behave the same to a web developer, but different to the user. For example, we would allow unlimited close watchers / cancel
event preventDefault()
s on both platforms, but sometimes on Android that would pop up a dialog to the user saying "this page seems to be trying to prevent you from leaving. Do you want to leave anyway?" and then the page would navigate away if the user said yes.
In the end these are all tradeoffs.
My preference is still the current spec auto-mitigation on both desktop and mobile, if we can get away with it. But if we cannot then I think I still prefer the current spec auto-mitigation on just mobile. The cost will be an increase in poorly-coded but non-malicious sites since testing on desktop won't automatically give the same behavior on mobile.
The prompt gives a malicious site a window for further abuse I suppose, but maybe that's okay (as the user should be safe either way).
If you showModal() many
<dialog>
s without user activation, only the first (bottommost) will be closeable with Esc. Others will ignore close signals. (This avoids creating tons of<dialog>
s on Android which consume all the back button presses.)
This WPT tests this behavior: https://github.com/web-platform-tests/wpt/blob/9beb905959/html/semantics/interactive-elements/the-dialog-element/dialog-canceling.html https://wpt.fyi/results/html/semantics/interactive-elements/the-dialog-element/dialog-canceling.html?label=experimental&label=master&aligned If we choose to do full CloseWatcher for dialog, I would have to basically invert the expectations.
On one hand, websites probably don't open multiple modal dialogs at the same time, right...? Maybe I should add a UseCounter for this.
On the other hand, the escape key isn't used to navigate the page like the back button does on android, so I don't see why there should be any CloseWatcher user activation stuff with the escape key. If CloseWatcher could consume the navigate back button in the browser UI on desktop, then it would be easy choice to do the same on android and desktop.
Does CloseWatcher do anything on desktop besides consume the escape key?
@josepharhar the idea is that a developer doesn't need to specifically support a particular platform: whatever the most natural gesture to cancel is present on the platform - the dialog implementation propagates it as a cancel signal.
To recap: after #23, the potential behavior changes for <dialog>
if we ship https://wicg.github.io/close-watcher/#patch-dialog are:
Sometimes a single close signal will close multiple <dialog>
s. This should be very rare: it requires opening multiple <dialog>
s without any user activation between them, and the "free" CloseWatcher/<dialog>
gives us some buffer.
Sometimes a cancel
event will not be fired. This occurs if the user doesn't interact with the dialog at all, before sending a close signal. This should be relatively rare by multiplying numbers: modal dialogs are still somewhat rare only some dialogs get closed by close signals only some dialogs have cancel
listeners and thus would be impacted by this change * only sometimes does the user cancel out of a dialog without doing anything.
I hope to add use counters to capture how often these cases would come up, to help us determine whether changing behavior in these cases is feasible.
The use counters came back very low, and we resolved this compat issue to be negligible:
The current spec attempts to integrate
<dialog>
with close watchers very directly. However, due to the anti-abuse restrictions, this breaks compat on desktop OSes in some cases.As background, our anti-abuse restrictions are that you basically get to intercept one close signal per user activation, to avoid back trapping with the Android back button. If you try to intercept more, you will either not be able to create a
CloseWatcher
, or you will not get acancel
event.However, we apply those restrictions uniformly across platforms, including on desktop platforms where the signal is the non-abusable Esc key. The idea is to avoid platform-specific differences and make it easier to test-once, run-on-any-user's-device.
This seems fine for the new
CloseWatcher
class. But for<dialog>
this does have compat impacts:showModal()
many<dialog>
s without user activation, only the first (bottommost) will be closeable with Esc. Others will ignore close signals. (This avoids creating tons of<dialog>
s on Android which consume all the back button presses.)cancel
event will not fire. (Since thecancel
event can bepreventDefault()
ed, which consumes a close signal, which we don't want to let happen an unlimited number of times.)I think these behaviors are good for integrating the Android back button with
<dialog>
s. (Note that no browser has such integration today, so it's a question about whether the proposed integration, subject to the above restrictions, is better than nothing.)And I think in the real world these restrictions should be survivable for
<dialog>
s even on desktop. People should generally not open more than one<dialog>
without user activation. But, it is a concern.Ideas:
Leave it as is, and take the compat hit. IMO it will be manageable, or at least worth trying, and the benefit of getting uniform behavior across mobile and desktop is worth it.
<dialog>
gets special-casing for Esc key handling to preserve compat. Basically if the close signal is an Esc key, we bypass the usual checks and use a separate path for reacting to that, instead of using the close signal infrastructure.<dialog>
special powers compared to what a web developer could write. It's just messy. See below for more.<dialog>
still firescancel
events, but they are not cancelable if there haven't been enough user activation. This is a quick fix that might help people who happen to be using<dialog>
'scancel
as a synonym forclose
instead of using it as a method of preventing the dialog from closing.We change the close watcher infrastructure in general to only apply anti-abuse measures on close signals where it is necessary (e.g. Android). This means that if you are working on desktop, you can create unlimited
CloseWatcher
instances and get unlimitedcancel
events, since consuming Esc key presses is not dangerous. Similarly on iOS devices (although there close signals are rare). But if you are working on Android thenew CloseWatcher()
constructor might throw, or the resultingCloseWatcher
might not fire acancel
event.new CloseWatcher()
throwing, it returns an already-deactivatedCloseWatcher
that will never fire events, which might be a bit less destructive for those who only test on desktop.CloseWatcher
only on Android, or listening for Esc in addition to using theCloseWatcher
./cc @smaug---- @annevk @josepharhar