From a9f103c9f7bd09ef712990194638c75db1f50e3c Mon Sep 17 00:00:00 2001 From: Joey Arhar Date: Thu, 26 Jan 2023 01:50:28 -0800 Subject: [PATCH] Implement dialog initial focus proposal This implements the changes proposed here: https://github.com/whatwg/html/wiki/dialog--initial-focus,-a-proposal#dialog-draft-text Specifically: 1. Make the dialog focusing steps look at sequentially focusable elements instead of any focusable element. 2. Make the dialog element itself get focus if it has the autofocus="" attribute set. 3. Make the dialog element itself get focus as a fallback instead of focus being reset to the body element. Closes #1929. Closes #2197. Closes #4184. Additional dialog issues remain open at https://github.com/whatwg/html/labels/topic%3A%20dialog. --- source | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 112 insertions(+), 14 deletions(-) diff --git a/source b/source index 241fbae3d07..19f21482a73 100644 --- a/source +++ b/source @@ -59187,8 +59187,88 @@ interface HTMLDialogElement : HTMLElement {
Uses HTMLDialogElement.
-

The dialog element represents a part of an application that a user interacts with - to perform a task, for example a dialog box, inspector, or window.

+

The dialog element represents a transitory part of an application, in the form of + a small window ("dialog box"), which the user interacts with to perform a task or gather + information. Once the user is done, the dialog can be automatically closed by the application, or + manually closed by the user.

+ +

Especially for modal dialogs, which are a familiar pattern across all types of applications, + authors should work to ensure that dialogs in their web applications behave in a way that is + familiar to users of non-web applications.

+ +

As with all HTML elements, it is not conforming to use the dialog + element when attempting to represent another type of control. For example, context menus, + tooltips, and popup listboxes are not dialog boxes, so abusing the dialog element to + implement these patterns is incorrect.

+ +

An important part of user-facing dialog behavior is the placement of initial focus. The + dialog focusing steps attempt to pick a good candidate for initial focus when a + dialog is shown, but might not be a substitute for authors carefully thinking through the correct + choice to match user expectations for a specific dialog. As such, authors should use the autofocus attribute on the descendant element of the dialog that + the user is expected to immediately interact with after the dialog opens. If there is no such + element, then authors should use the autofocus attribute + on the dialog element itself.

+ +
+

In the following example, a dialog is used for editing the details of a product in an + inventory management web application.

+ +
<dialog>
+  <label>Product Number <input type="text" readonly></label>
+  <label>Product Name <input type="text" autofocus></label>
+</dialog>
+ +

If the autofocus attribute was not present, the + Product Number field would have been focused by the dialog focusing steps. Although that is + reasonable behavior, the author determined that the more relevant field to focus was the Product + Name field, as the Product Number field is readonly and expects no user input. So, the author + used autofocus to override the default.

+ +

Even if the author wants to focus the Product Number field by default, they are best off + explicitly specifying that by using autofocus on that input element. This makes the + intent obvious to future readers of the code, and ensures the code stays robust in the face of + future updates. (For example, if another developer added a close button, and positioned it in the + node tree before the Product Number field).

+
+ +

Another important aspect of user behavior is whether dialogs are scrollable or not. In some + cases, overflow (and thus scrollability) cannot be avoided, e.g., when it is caused by the user's + high text zoom settings. But in general, scrollable dialogs are not expected by users. Adding + large text nodes directly to dialog elements is particularly bad as this is likely to cause the + dialog element itself to overflow. Authors are best off avoiding them.

+ +
+

The following terms of service dialog respects the above suggestions.

+ +
<dialog style="height: 80vh;">
+  <div style="overflow: auto; height: 60vh;" autofocus>
+    <p>By placing an order via this Web site on the first day of the fourth month of the year
+    2010 Anno Domini, you agree to grant Us a non-transferable option to claim, for now and for
+    ever more, your immortal soul.</p>
+    <p>Should We wish to exercise this option, you agree to surrender your immortal soul,
+    and any claim you may have on it, within 5 (five) working days of receiving written
+    notification from  this site or one of its duly authorized minions.</p>
+    <!-- ... etc., with many more <p> elements ... -->
+  </div>
+  <form method="dialog">
+    <button type="submit" value="agree">Agree</button>
+    <button type="submit" value="disagree">Disagree</button>
+  </form>
+</dialog>
+ +

Note how the dialog focusing steps would have picked the scrollable + div element by default, but similarly to the previous example, we have placed autofocus on the div so as to be more explicit and + robust against future changes.

+ +

In contrast, if the p elements expressing the terms of service did not have such + a wrapper div element, then the dialog itself would become scrollable, + violating the above advice. Furthermore, in the absence of any autofocus attribute, such a markup pattern would have violated + the above advice and tripped up the dialog focusing steps's default behavior, and + caused focus to jump to the Agree button, which is a bad user experience.

+

The open attribute is a boolean attribute. When specified, it indicates that the dialog @@ -59276,7 +59356,8 @@ interface HTMLDialogElement : HTMLElement {

  • Set the dialog element's previously focused element to the focused element.

  • -
  • Run the dialog focusing steps for the dialog element.

  • +
  • Run the dialog focusing steps given the dialog element and + false.

  • When the HTMLDialogElement : HTMLElement {

  • Set the subject's previously focused element to the focused element.

  • -
  • Run the dialog focusing steps for subject.

  • +
  • Run the dialog focusing steps given subject and true.

  • -

    The dialog focusing steps for a dialog element subject are as follows:

    +

    The dialog focusing steps, given a dialog element subject + and a boolean isModal, are as follows:

      -
    1. Let control be the focus delegate of subject.

    2. +
    3. Let control be null.

    4. + +
    5. If isModal is true and subject has the autofocus attribute, then set control to + subject.

    6. + +
    7. If control is null, then set control to the focus + delegate of subject.

    8. If control is null, then set control to subject.

    9. Run the focusing steps for control.

      -

      If control is not focusable, this will do nothing. For - modal dialogs, this means that any earlier - modifications to the focused area of the document will apply.

      +

      If control is not focusable, this will do nothing. This + would only happen if subject had no focus delegate, and the user agent decided that + dialog elements were not generally focusable. In that case, any earlier modifications to the focused area of the + document will apply.

    10. Let topDocument be control's node navigable's Navigator { The element itself. -

      iframe, <input - type=text>, sometimes <a href=""> (depending on platform - conventions). +

      iframe, dialog, <input type=text>, sometimes <a + href=""> (depending on platform conventions). @@ -76864,11 +76955,18 @@ partial interface Navigator { order:

        -
      1. If descendant is a focusable area, then return +

      2. Let focusableArea be null.

      3. + +
      4. If focusTarget is a dialog element and descendant is + sequentially focusable, then set focusableArea to + descendant.

      5. + +
      6. Otherwise, if focusTarget is not a dialog and + descendant is a focusable area, set focusableArea to descendant.

      7. -

        Let focusableArea be the result of getting the focusable area for descendant given focusTrigger.