A user account is required in order to edit this wiki, but we've had to disable public user registrations due to spam.

To request an account, ask an autoconfirmed user on Chat (such as one of these permanent autoconfirmed members).


From WHATWG Wiki
Jump to navigation Jump to search

Problem statement

There's no markup or API for dialog boxes, tool palettes, hovering tooltips, the contents of popup widgets, and the like.

Real world examples today


Registration Dialogs

<img src=http://junkyard.damowmow.com/477>

  • http://digg.com/ - make sure to be logged out if you have an account, and click the Join Digg! button

<img src=http://junkyard.damowmow.com/480>

<img src=http://junkyard.damowmow.com/478>

Login Dialogs

  • http://slashdot.org/ - make sure to be logged out if you have an account, and click the Log In link
  • http://digg.com/ - make sure to be logged out if you have an account, and click the Login button
  • http://newsvine.com/ - make sure to be logged out if you have an account, and click the Log In | Register link
  • http://www.bahn.de/ - Login link is rightmost in main navigation bar - try tapping: funny handling of focus order, skipping positions, at times keyboard trap


These are "dialogs" in the sense that they are modal boxes that accept input, but they are typically anchored to some other UI, not centered in the viewport.

  • Google Calendar's "create" widget

<img src=http://junkyard.damowmow.com/483>

  • Google+'s speedbumps

<img src=http://junkyard.damowmow.com/484> <img src=http://junkyard.damowmow.com/487>

Other Dialogs

  • http://www.kongregate.com/ - register for account, log in, click Get Kreds, click Fund Your Account button
  • GMail - Click "more" on the left, then Create New Label.

<img src=http://junkyard.damowmow.com/491>

  • Google+ circle editor

<img src=http://junkyard.damowmow.com/486>

  • Google+ hovercard UI

<img src=http://junkyard.damowmow.com/490>

  • iCloud's login error message box — note animation during display

<img src=http://junkyard.damowmow.com/488> <img src=http://junkyard.damowmow.com/489>


Some of these appear on mouseover, some on click, and some on load. Some of them dismiss when the mouse moves away, some have to be explicitly dismissed. The distinguishing factor though is that these are not model — you can interact with other stuff on the page while they are up (in the simplest case, selecting the text from which they appeared).

  • Digg has one when you click on something when logged out.

<img src=http://junkyard.damowmow.com/479>

  • The tooltips in the table of [1] are interesting because they are currently <div>s and force the parent to be a TD rather than a TH since TH is inline only, even though the visible content is really just phrasing content. They appear on mouse over.

<img src=http://junkyard.damowmow.com/481>

  • GMail's contacts list has rich tooltips that appear on mouse over.
  • Google Docs and GMail have some that appear on load

<img src=http://junkyard.damowmow.com/482> <img src=http://junkyard.damowmow.com/492>

  • Google+ has one for when you add someone -- the rest of the page is still interactive (though using any other widget makes this one go away).

<img src=http://junkyard.damowmow.com/485>


Code Examples



<a href="#" onclick="return showcover(false);">register</a>
<div class="login-popup cover-overlay" style="display: none; "
    <div class="cover" onclick="return hidecover(this)"></div>
    <div class="popup">


function showcover(a, b) {
    $(".login-popup:first").show().find('form input[name="reason"]').val(b || "");
    return !1
function hidecover(a) {
    return !1

(showcover() has been truncated to remove code not relevant to showing the dialog: if variable a is set as 'true', another element (not found in this page) is also shown)


.popup {
  position: fixed;
  left: 10%;
  background-color: white;
  top: 40px;
  width: 80%;
  z-index: 1001;
.cover {
  position: fixed;
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
  background-color: gray;
  opacity: .7;
  z-index: 1000;



<div id="modal_cover" class="push" onclick="hide_modal_box(); return false;" style="display: none;"></div>
<div id="modal_box" class="push" style="display: none;">
   <div id="modal_box_content">...</div>

<a href="//slashdot.org/my/newuser" onclick="javascript:getModalPrefs('newUserModal', 'Create Account', 1); $('#modal_box').addClass('join'); return false;" class="btn link">Join</a>

Javascript: (getModalPrefs has been truncated to remove code not relevant to showing the dialog)

function getModalPrefs(section, title, tabbed, params) {
    Slash.busy(BUSY_FETCHING_MODAL, true);
    $bg = get_modal_parts('#modal_cover').css('opacity', 0.75).show();
    $any('modal_box_content').load('/ajax.pl', $.extend({op: this_op,section: section,reskey: reskey_static,tabbed: tabbed,return_to: return_to}, params || null), function(response, status, transport) {
        if (status === 'success') {
            var $modal = show_modal_box().data('tabbed', tabbed);
            tabbed && $modal.addClass("tabbed");
        } else {
        Slash.busy(BUSY_FETCHING_MODAL, false);

function show_modal_box() {
    return custom_modal_box('show').keyup(function(e) {
        e.which == $.ui.keyCode.ESCAPE && hide_modal_box();

function hide_modal_box() {
    var retainclass = " ";
    if ($('#modal_box').hasClass('push')) {
        retainclasses = 'push';
    custom_modal_box('hide').hide().attr('style', 'display: none;').removeClass().addClass(retainclasses).removeData('tabbed').unbind();
    if (document.forms.modal_prefs && document.forms.modal_prefs.refresh_onclose && document.forms.modal_prefs.refresh_onclose.value) {
        document.location = document.URL;
    return false;


#modal_box.join {
  margin: 0px 33% 0;
  width: 390px;
  height: 440px;
#embbeded_login_modal.push, #modal_box.push {
  margin-top: 9em !important;
#modal_box {
  position: fixed;
  z-index: 1000001;
#modal_cover {
  margin-top: -12px;
  margin-left: -13px;
  background: rgba(0, 0, 0, .6);
  height: 100%;
  position: fixed;
  width: 100%;
  z-index: 1000000;

DB Dahn


<li id="mn-login" class="rollover">
    <a href="https://fahrkarten.bahn.de/privatkunde/start/start.post?lang=de&scope=login" id="login" class="jhover" rel="nofollow"><span>Login</span></a>

If #mn-login is given class of rollover (done using javascript on focus and mouseover, removed on blur, the h3 and ul tags are displayed in CSS:

#main-nav ul ul, #main-nav ul h3 {
  border: 1px solid #9FA3AB;
  display: none;
  left: -9999em;
  position: absolute;
#main-nav li#mn-login.rollover h3 {
  left: -6px;
#main-nav li#mn-login.rollover ul {
  left: auto;
  right: 6px;


Early Ideas

(These are random ideas inspired by the above and similar APIs in other languages. They need careful evaluation and are not a proposal.)

  • have to handle showing an element that's descendant of display:none content; does that just not count?
  • callbacks as arguments to show() and especially showModal(), as in, dialog.showModal(function (returnValue) { ... })


  • <dialog>
    • can be used as flow, or as child of <th> or <dt>. Can't be used in <hx> due to parsing problems (it couldn't contain its own heading).
    • semantically it's like hidden="", the contents aren't considered part of the parent.
    • sectioning root.
  • <dialog open> attribute is set when dialog is showing.
    • dialog:not([open]) { display: none; } /* allows authors to do transitions if they want */
  • lightboxes are handled by the <dialog> being width:100%;height:100%; or some such
  • rely on CSS for all styling except positioning (for now)
  • dialog.showModal([anchor]); or modal="" and show([anchor])
    • dialog is focused when displayed
    • everything else in the document is made unfocusable
    • escape key fires 'cancel' event; default behaviour is to call close() with empty string as value
    • dialog.oncancel event handler
    • push onto fullscreen stack
    • obtain a dialog::backdrop
      • only active if the dialog was shown with showModal(); has magic positioning that covers the whole viewport under the dialog regardless of scrolling.
      • animatable separate form the dialog element itself, so you can fade it in then the dialog.
      • dialog.onclickoutside event handler fires if user clicks on the cover
    • z-index: magic to keep on top of anything displayed before it
  • dialog.show([anchor]);
    • shows the dialog
  • dialogs can be opened without anchors
    • causes the dialog to be absolutely positioned with explicit top and left/right (based on rtl) so that its margin box is centered in current viewport, but margin top edge is not above top of viewport.
    • [let JS do this:] dialog can be drag moved which affects the left and top/right
  • dialogs opened with anchors
    • anchor can be an element or a MouseEvent. If it's an element, the anchor point is the center of the given element's first box. Otherwise it's the mouse position given by the event.
    • displays the dialog, anchored so that its anchor point is at the point given by the show() method argument.
    • follows anchor point
    • anchor point comes from 'anchor' property? anchor: (top|bottom|left|right) [center | <length> [from (top|bottom|left|right)]]; uses given point on margin box edge
    • can't be drag moved.
  • dialog.close([returnValue]) sets dialog.returnValue if value is given, and closes the dialog
  • dialog.returnValue is a string
  • dialog.onclose event handler
  • <form method=dialog>
    • only valid inside <dialog>
    • makes submission hide the dialog and call the close callback
    • on submission, dialog.returnValue is set to the value of the submit button that was used

Other brainstorms

(Proposals for similar or related functionality found elsewhere.)