[whatwg] Comments on <dialog>

Ian Hickson ian at hixie.ch
Tue Dec 17 12:14:58 PST 2013

On Sat, 2 Nov 2013, Brian Blakely wrote:
> On Sat, Nov 2, 2013 at 5:29 PM, Ian Hickson <ian at hixie.ch> wrote:
> > On Sat, 2 Nov 2013, Brian Blakely wrote:
> > >
> > > 1. When a modal dialog is active, the user can still scroll the 
> > > underlying page.
> >
> > Why is that a bug?
> By its nature, a modal view blocks interaction with the underlying 
> content.
> It's also inherently disorienting.  Imagine opening a modal, 
> accidentally scrolling the underlying page while interacting with said 
> modal, then closing the modal and seeing something totally different 
> from before and not understanding why.  This happens today with the 
> majority of our "lightbox" plugins, and we have the opportunity to fix 
> it now.

I've changed the spec to make the ancestors of <dialog>s inert, so this 
should be fixed now.

> > > 2. Even if the root element has overflow hidden, it should be 
> > > possible to scroll the modal "layer" when a dialog escapes the 
> > > boundaries of the viewport (or iframe).
> >
> > Why? Isn't the whole point of 'overflow: hidden' on the root element 
> > to prevent the ability to move the viewport?
> >
> > You can always but the overflow property on a child of the <body>, 
> > e.g. a fixed positioned <div>. Then the scrollbars would be hidden for 
> > the div, but the viewport could still be moved for dialogs.
> <div> wrappers are what we use today, and are what <dialog> should be 
> alleviating.  Maybe ::backdrop should be a pseudo-parent for <dialog>, 
> with overflow: auto by default.  At the very least, that would be a much 
> more flexible solution going forward.

This is an interesting issue. Right now, arguably, even if the dialog 
isn't 'fixed' and the viewport isn't 'overflow:hidden', it's not clear 
that you can scroll if the dialog doesn't fit, because of the fix to the 
problem described above -- it's the same scrolling mechanism that scrolls 
the view of the dialog as scrolls the parent's contents -- in fact, the 
dialog is just part of the parent's contents.

I'm not sure what the right answer is here. For dialogs whose containing 
block is the initial containing block, maybe we can require that, as a 
special case, the browser allow the viewport to be moved around to view 
the dialog (but then what happens if it _is_ overflow:hidden and the 
dialog goes away? Does it snap back? What about the background, what do we 
show in the parts the author never intended to have visible?). But what 
about when the dialog is in a <div> with overflow:scroll, if it's not 
absolutely positioned?

I guess that's a rare case (and you can't position a dialog inside an 
overflow:scroll element because of the rule about the containing block for 
<dialog> elements), so maybe we ignore it.

I've added a rule to the spec that says that viewports have to be pannable 
so you can see all of a dialog, but I don't know how feasible that really is.

> > > 3. When the modal dialog's height changes, either due to CSS or 
> > > content changes, the vertical position of the dialog should change 
> > > (unless the height exceeds the viewport height).
> >
> > That's an interesting idea, but I'm not convinced it's the right 
> > answer. Having the dialog move up and down when stuff is added at the 
> > bottom would be quite weird. You can always implement this manually 
> > from script.
> To go back to hacky and rather difficult-to-maintain JS techniques for 
> something so simple seems antithetical to the intention of <dialog> to 
> me. Modern modal implementations don't require that.

My point isn't that we shouldn't offer the feature because it is already 
possible. My point is that this feature is actively bad. I'm saying I 
don't think it's good UI for the dialog position to change when it 
increases in height.

On Tue, 17 Dec 2013, Matt Falkenhagen wrote:
> On Fri, Sep 27, 2013 at 7:15 AM, Ian Hickson <ian at hixie.ch> wrote:
> >
> > I started doing this, since several people have asked about this and 
> > it seems the consistency between showModalDialog()/close() seems less 
> > interesting to people than the consistency with "open" everywhere 
> > else. However, it turns out this would make the show() method clash 
> > with the "open" IDL attribute on <dialog>, which we want since it 
> > matches the name of the open="" content attribute which matches 
> > <details open>.
> >
> > Note that window.open() and document.open() don't really do the same 
> > as this method does, either. window.open() creates a new Window, or 
> > navigates and existing one; document.open() resets the document. 
> > dialog.show() just changes the dialog to be visible.
> >
> > Also, there's an interesting mix in other APIs. (Disclaimer: I don't 
> > know many of these APIs personally, so I may be misinterpreting their 
> > documentation wildly. I basically looked for terms like "open" and 
> > "close" in the docs and tried to see what the right methods were in 
> > each case. I only included methods for modal dialogs if there was a 
> > trivial method; many APIs have to be configured to make dialogs modals 
> > separately.)
> >
> >  Android uses show() and dismiss()
> >  Closure uses setVisible()
> >  Cocoa uses makeKeyAndOrderFront:, orderOut:, close, and performClose:.
> >  Delphi uses Show(), ShowModal(), Hide(), and Close().
> >  Ext JS uses show(), hide(), and close().
> >  jQuery uses "open" and "close".
> >  Gtk uses gtk_widget_show(), gtk_dialog_run(), gtk_window_close().
> Gtk also has gtk_widget_hide(), see [0]

What's the difference between gtk_window_close and gtk_widget_hide? I 
couldn't tell from the documentation.

> >  .NET uses Show(), ShowDialog(), Hide(), and Close().
> >  Win32 uses ShowWindow() and CloseWindow().
> >  X11 uses XMapWindow() and XUnmapWindow()
> >
> > Most of the APIs I looked at use "close". Most use "show". So I think 
> > we're in ok company here.
> Sorry to add feedback so late. Whenever there's a post/tweet about 
> Chrome's <dialog>, the most common complaint from devs seems to be this 
> show/close naming.

It's certainly a common complaint, but I don't understand why, given the 
existing naming conventions.

> In the list of existing APIs above, only Win32 has only show/close.

Delphi's Hide() and Close() are different. Close() is what you need to end 
a dialog's modal loop -- it sets a return value and hides the dialog. This 
is distinct from just Hide(), which makes the dialog invisible but keeps 
it modal. That is, conceptually, if this is a conversation the user is 
having with someone, Hide() is like that person stepping out of the way to 
afford the user a better view of the topic of conversation, while Close() 
is that person leaving the conversation.

The semantic of Delphi's Close() is closer to what I'm looking for here.

> Of APIs that have all of show/hide/close, it looks like close does 
> something like dispose of the object/free its memory so it can't be 
> shown again [...] So show/hide for <dialog> seems more consistent than 
> show/close with these APIs.

I don't know if it's that simple. As noted above for Delphi's case, 
there's a difference between "hide" and "close", in that "hide" is just a 
matter of opacity, and "close" is when the dialog ends its life. In the 
case of HTML, you can set hidden="" on a <dialog>, and you can close it. 
Closing it does much more, e.g. setting returnValue, removing it from the 
pending dialog stack, firing events, etc. Yes, the dialog can be reused, 
it's not destroyed, but it's also not merely hidden.

> Some additional data points:

Thanks for the data. (Thanks also for the references.)

So let's go through the list again.

First let's put aside the ones that can't really help us. setVisible() 
doesn't fit any of the relevant idioms on the Web, so let's ignore those. 
We can also ignore X11 and Xt, which have their own idioms:

   Closure: setVisible()
   Java AWT: setVisible() (deprecated alternatives listed below)
   X11: XMapWindow(), XUnmapWindow()
   Xt: XtPopup(), XtPopdown()

For opening the dialog, "open" is surprisingly rarely used. The only 
examples we found were HTML itself, and jQuery:

   HTML: window.open(), window.showModalDialog(), window.close()
   jQuery: "open", "close"

BTW, jQuery actually does also use "show" for relevant API surface; it 
gives instructions on how to animate the opening of the dialog.

Of all those that remain, only Cocoa doesn't use "show", and what it uses 
is Cocoa-specific:

   Cocoa: makeKeyAndOrderFront:, orderOut:, close, performClose:

So it seems reasonable to use "show" for opening the dialog. For the modal 
case, we have ShowDialog(), ShowModal(), ..._run(), and showModalDialog(). 
ShowModal() appears twice, three times if you include showModalDialog().

Based on this, it seems reasonable to go with show() and showModal().

So that leaves the opposite end of the conversation. Here, Android is an 
outlier, so let's ignore that:

   Android: show(), dismiss()

There's some that use some special names other than hide or close, e.g. 
wxWindows, which has Show(false) and EndModal():

   wxWindows: Show(true), ShowModal(), Show(false), EndModal(), Close()

...and Qt, which really uses done() to close a dialog, not close(), since 
close() doesn't set the return value.

(I'm ignoring "destroy" since many of these APIs have destructors with 
similar names, but those aren't really what we're looking for here.)

So with that out of the way, there's five (four if you ignore the 
deprecated one) that only use "hide", not "close", as the key term:

   Bootstrap: show(), hide()
   Dojo: show(), hide()
   GWT: show(), hide()
   YUI: show(), hide()
   Java AWT deprecated API: show(), hide()

There's five that use "close", not "hide", paired with either "show" or 
"open", plus Cocoa which uses "close", not "hide", but has other terms 
for opening, as mentioned earlier (Cocoa does use "hide" in some of its 
related APIs, but not as an imperative):

   Blackberry: show(), close()
   Win32: ShowWindow(), CloseWindow().
   jQuery: "open", "close"
   HTML: window.open(), window.showModalDialog(), window.close()
   wxWindows: Show(true), ShowModal(), Show(false), EndModal(), Close()
   Cocoa: makeKeyAndOrderFront:, orderOut:, close, performClose:

There's some that use both (though in all three cases I would argue that 
their use of "Close" is closer to what we want than their use of "Hide"):

   .NET: Show(), ShowDialog(), Hide(), Close()
   Delphi: Show(), ShowModal(), Hide(), Close()
   Ext JS: show(), hide(), close()

...and then there's some special cases, like Qt, mentioned above, where 
"done" is the one with the semantic we want, but where "close" and "hide" 
are also available with slightly different semantics:

   Qt: show(), hide(), close(), done()

...or Gtk, where the _window/dialog_ logic uses close(), but where you can 
also use the "inherited" hide() as far as I can tell:

   Gtk: gtk_widget_show(), gtk_dialog_run(), gtk_widget_hide(), gtk_window_close()

This leads me to the same conclusion as before. show()/close() is the 
combination most consistent with existing APIs.

But I think that's ok. We do _have_ "hide" in our API, it's just (like in 
Cocoa's case) not used as an imperative term, but as an attribute.

   <dialog open="">
   <dialog hidden="">
   <dialog open="" hidden="">
   dialog.open = true;
   dialog.open = false;
   dialog.hidden = true;
   dialog.hidden = false;
   dialog.returnValue = result;

"open" is the state meaning the dialog is up.

"hidden" is the state meaning the rendering is not visible, which 
overrides "open". (Not dialog-specific.)

show() sets open to true and positions the dialog.

showModal() sets open to true, positions the dialog, and sets up the 

close() sets the return value and sets open to false, unwinding the 
modality if necessary.

We could use open()/openModal()/close() and have opened="" or isopen="" 
(after jQuery's "isOpen" and HTML's ismap=""), but the inconsistency with 
<details> would be hard to square, IMHO. And pretty much none of the APIs 
above use "open". They almost all use "show". We could do show/hide 
instead of show/close, and still use open="" for the visible state, but 
then there's the confusing similarity with hidden="" (it's very odd for 
hide() to remove open() rather than adding hidden="").

We could reuse hidden="" instead of open="". The problem there is that 
you'd have to always be declaring dialogs as <dialog hidden="">, which is 
pretty lame (that's why I made the default be hidden and used open="" to 
show the dialogs).

I dunno. I certainly agree that it's weird to not have the two opposite 
imperative methods be antonyms. It's just that internal inconsistency is 
even worse than that.

My conclusion is that it's a tough call, but the current API is probably 
the least bad compromise (there's a resounding endorsement, eh?). I'm not 
the final decider on this, though; that would be the browser vendors. I 
believe Blink is currently getting an implementation of this; if you can 
convince whoever is writing that code to use a different API, then I'll 
change the spec accordingly. Please do consider the whole language when 
doing so, though, not just <dialog>. A non-antonym pair of terms in an API 
is something you can learn easily enough; figuring out when to use open="" 
and when to use opened="" is much harder, especially when they're right 
next to each other.

Ian Hickson               U+1047E                )\._.,--....,'``.    fL
http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

More information about the whatwg mailing list