Skip to content

Commit

Permalink
Implement dialog initial focus proposal
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
josepharhar authored Jan 26, 2023
1 parent e3c56ca commit a9f103c
Showing 1 changed file with 112 additions and 14 deletions.
126 changes: 112 additions & 14 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -59187,8 +59187,88 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<dd w-dev>Uses <code>HTMLDialogElement</code>.</dd>
</dl>

<p>The <code>dialog</code> element represents a part of an application that a user interacts with
to perform a task, for example a dialog box, inspector, or window.</p>
<p>The <code>dialog</code> 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.</p>

<p>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.</p>

<p class="note">As with all HTML elements, it is not conforming to use the <code>dialog</code>
element when attempting to represent another type of control. For example, context menus,
tooltips, and popup listboxes are not dialog boxes, so abusing the <code>dialog</code> element to
implement these patterns is incorrect.</p>

<p>An important part of user-facing dialog behavior is the placement of initial focus. The
<span>dialog focusing steps</span> 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 <code
data-x="attr-fe-autofocus">autofocus</code> 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 <code data-x="attr-fe-autofocus">autofocus</code> attribute
on the <code>dialog</code> element itself.</p>

<div class="example">
<p>In the following example, a dialog is used for editing the details of a product in an
inventory management web application.</p>

<pre><code class="html">&lt;dialog>
&lt;label>Product Number &lt;input type="text" readonly>&lt;/label>
&lt;label>Product Name &lt;input type="text" autofocus>&lt;/label>
&lt;/dialog></code></pre>

<p>If the <code data-x="attr-fe-autofocus">autofocus</code> 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.</p>

<p>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 <code>input</code> 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).</p>
</div>

<p>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.</p>

<div class="example">
<p>The following terms of service dialog respects the above suggestions.</p>

<pre><code class="html">&lt;dialog style="height: 80vh;">
&lt;div style="overflow: auto; height: 60vh;" autofocus>
&lt;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.&lt;/p>
&lt;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.&lt;/p>
&lt;!-- ... etc., with many more &lt;p> elements ... -->
&lt;/div>
&lt;form method="dialog">
&lt;button type="submit" value="agree">Agree&lt;/button>
&lt;button type="submit" value="disagree">Disagree&lt;/button>
&lt;/form>
&lt;/dialog></code></pre>

<p>Note how the <span>dialog focusing steps</span> would have picked the scrollable
<code>div</code> element by default, but similarly to the previous example, we have placed <code
data-x="attr-fe-autofocus">autofocus</code> on the <code>div</code> so as to be more explicit and
robust against future changes.</p>

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

<p>The <dfn element-attr for="dialog"><code data-x="attr-dialog-open">open</code></dfn> attribute
is a <span>boolean attribute</span>. When specified, it indicates that the <code>dialog</code>
Expand Down Expand Up @@ -59276,7 +59356,8 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<li><p>Set the <code>dialog</code> element's <span>previously focused element</span> to the
<span>focused</span> element.</p></li>

<li><p>Run the <span>dialog focusing steps</span> for the <code>dialog</code> element.</p></li>
<li><p>Run the <span>dialog focusing steps</span> given the <code>dialog</code> element and
false.</p></li>
</ol>

<p>When the <dfn method for="HTMLDialogElement"><code
Expand Down Expand Up @@ -59318,22 +59399,32 @@ interface <dfn interface>HTMLDialogElement</dfn> : <span>HTMLElement</span> {
<li><p>Set the <var>subject</var>'s <span>previously focused element</span> to the
<span>focused</span> element.</p></li>

<li><p>Run the <span>dialog focusing steps</span> for <var>subject</var>.</p></li>
<li><p>Run the <span>dialog focusing steps</span> given <var>subject</var> and true.</p></li>
</ol>

<p>The <dfn>dialog focusing steps</dfn> for a <code>dialog</code> element <var>subject</var> are as follows:</p>
<p>The <dfn>dialog focusing steps</dfn>, given a <code>dialog</code> element <var>subject</var>
and a boolean <var>isModal</var>, are as follows:</p>

<ol>
<li><p>Let <var>control</var> be the <span>focus delegate</span> of <var>subject</var>.</p></li>
<li><p>Let <var>control</var> be null.</p></li>

<li><p>If <var>isModal</var> is true and <var>subject</var> has the <code
data-x="attr-fe-autofocus">autofocus</code> attribute, then set <var>control</var> to
<var>subject</var>.</p></li>

<li><p>If <var>control</var> is null, then set <var>control</var> to the <span>focus
delegate</span> of <var>subject</var>.</p></li>

<li><p>If <var>control</var> is null, then set <var>control</var> to <var>subject</var>.</p></li>

<li>
<p>Run the <span>focusing steps</span> for <var>control</var>.</p>

<p class="note">If <var>control</var> is not <span>focusable</span>, this will do nothing. For
modal dialogs, this means that any <a href="#note-dialog-plus-focus-fixup">earlier
modifications</a> to the <span>focused area of the document</span> will apply.</p>
<p class="note">If <var>control</var> is not <span>focusable</span>, this will do nothing. This
would only happen if subject had no focus delegate, and the user agent decided that
<code>dialog</code> elements were not generally focusable. In that case, any <a
href="#note-dialog-plus-focus-fixup">earlier modifications</a> to the <span>focused area of the
document</span> will apply.</p>
</li>

<li><p>Let <var>topDocument</var> be <var>control</var>'s <span>node navigable</span>'s <span
Expand Down Expand Up @@ -76245,9 +76336,9 @@ partial interface <span id="NavigatorUserActivation-partial">Navigator</span> {
The element itself.
<tr>
<td headers="td-fa-1 th-fa-examples" colspan=2>
<p class="example"><code>iframe</code>, <code data-x="attr-input-type-text">&lt;input
type=text></code>, sometimes <code data-x="a">&lt;a href=""></code> (depending on platform
conventions).
<p class="example"><code>iframe</code>, <code>dialog</code>, <code
data-x="attr-input-type-text">&lt;input type=text></code>, sometimes <code data-x="a">&lt;a
href=""></code> (depending on platform conventions).

<tbody>
<tr>
Expand Down Expand Up @@ -76864,11 +76955,18 @@ partial interface <span id="NavigatorUserActivation-partial">Navigator</span> {
order</span>:</p>

<ol>
<li><p>If <var>descendant</var> is a <span>focusable area</span>, then return
<li><p>Let <var>focusableArea</var> be null.</p></li>

<li><p>If <var>focusTarget</var> is a <code>dialog</code> element and <var>descendant</var> is
<span>sequentially focusable</span>, then set <var>focusableArea</var> to
<var>descendant</var>.</p></li>

<li><p>Otherwise, if <var>focusTarget</var> is not a <code>dialog</code> and
<var>descendant</var> is a <span>focusable area</span>, set <var>focusableArea</var> to
<var>descendant</var>.</p></li>

<li>
<p>Let <var>focusableArea</var> be the result of <span data-x="get the focusable
<p>Otherwise, set <var>focusableArea</var> to the result of <span data-x="get the focusable
area">getting the focusable area</span> for <var>descendant</var> given
<var>focusTrigger</var>.</p>

Expand Down

1 comment on commit a9f103c

@Subha
Copy link

@Subha Subha commented on a9f103c Jan 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can someone please help understand if this proposal is ever accepted and we can set autofocus="" in the dialog element itself?

Make the dialog element itself get focus if it has the autofocus="" attribute set.

Please sign in to comment.