Skip to content

Implement dialog initial focus proposal #8199

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Jan 26, 2023
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2394e21
Implement dialog initial focus proposal
josepharhar Jun 3, 2022
fd9c31d
add missing text from the proposal
josepharhar Aug 25, 2022
b52e9b6
add example
josepharhar Aug 25, 2022
8da9666
add second example
josepharhar Aug 25, 2022
2070d76
DialogShowOptions
josepharhar Aug 25, 2022
50c821f
Add showmodal autofocus logic
josepharhar Aug 26, 2022
844c49f
Merge remote-tracking branch 'upstream/main' into dialogsequentialfocus
josepharhar Sep 7, 2022
c15e1fc
remove a sentence with should
josepharhar Sep 7, 2022
4727fc0
link to methods
josepharhar Sep 7, 2022
8ff0298
dialogshowoptions
josepharhar Sep 7, 2022
da545c2
code input
josepharhar Sep 7, 2022
7003f1f
non-normative -> normative
josepharhar Sep 7, 2022
1ca7cbb
remove space
josepharhar Sep 7, 2022
7dae27e
add links to element types and attributes
josepharhar Sep 7, 2022
5907549
more normativeness
josepharhar Sep 7, 2022
b09e68c
dialog focusing steps link
josepharhar Sep 7, 2022
136592c
dialogshowoptions -> options
josepharhar Sep 7, 2022
1f0a278
preventinitialfocus stuff
josepharhar Sep 7, 2022
c6de43e
more preventinitialfocus linking
josepharhar Sep 7, 2022
e4046aa
remove explicit is modal parameter
josepharhar Sep 7, 2022
f60b5e2
more method
josepharhar Sep 7, 2022
3f56f1f
Merge with some upstream commits
josepharhar Oct 11, 2022
000aea4
respond to comments
josepharhar Oct 11, 2022
30683ac
make dialog element focusable sort of
josepharhar Oct 11, 2022
c95c97b
some nits
josepharhar Oct 17, 2022
133d817
Merge branch 'main' into dialogsequentialfocus
domenic Oct 22, 2022
76ed03e
annevk nits
josepharhar Oct 24, 2022
572a1c8
Merge branch 'main' into dialogsequentialfocus
josepharhar Oct 26, 2022
7585ed6
replace product number with add product
josepharhar Oct 26, 2022
9fe975a
remove extra space
josepharhar Oct 27, 2022
ca5d8e9
add pointer-events:none
josepharhar Nov 3, 2022
1763b9c
Revert "add pointer-events:none"
josepharhar Jan 11, 2023
ee1a835
Merge branch 'main' into dialogsequentialfocus
josepharhar Jan 17, 2023
b9c63ca
remove modeless note
josepharhar Jan 17, 2023
494d638
Revert "replace product number with add product"
josepharhar Jan 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 112 additions & 14 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -59129,8 +59129,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>
Copy link
Member

Choose a reason for hiding this comment

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

I'm sorry, this is totally on me, but I forgot why we changed this from the example at https://github.com/whatwg/html/wiki/dialog--initial-focus,-a-proposal#example . @scottaohara I vaguely remember you being involved?

I'm not very happy with this example because it's just hard to believe the web developer would put the button before the input. The example at https://github.com/whatwg/html/wiki/dialog--initial-focus,-a-proposal#example is more believable. If there's something wrong with my initial version (I vaguely recall there was), could we try to come up with a more believable example here?

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I found the conversation. It's at #8199 (comment) (collapsed by default). I guess @annevk didn't like the example because it relied on the focusablity of readonly controls? I don't think that's so strange. The point of readonly (as opposed to disabled) is explicitly to be focusable/selectable. E.g. it's what I use in the second textbox in https://domenic.github.io/rewrapper/ .

@annevk , are you OK reverting this to the previous example?

Copy link
Collaborator

Choose a reason for hiding this comment

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

agreed @domenic, far prefer the original example as this new one doesn't make sense. the original example is something i can point to many instances of in microsoft products.

i'm confused by the original comment, indicating that Firefox did not autofocus readonly controls. testing today, focus goes to the readonly text field just fine (chrome and firefox), as i'd expect. So maybe Firefox has reversed course to match up with other implementations since october?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok I tentatively reverted back to the previous example

Copy link
Member

Choose a reason for hiding this comment

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

Alright, fair enough.

&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
Copy link
Member

Choose a reason for hiding this comment

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

Is this intended to be non-normative? If so, don't use "should".

Copy link
Member

Choose a reason for hiding this comment

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

I intended this to be normative when I wrote it. Do you think it's a bad normative requirement, e.g. because it's too vague? I'm not sure on the precedent there.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry for the delay. Yes, I think it's not a good requirement because it's vague and not testable. Further, the wording "authors should work to ensure" makes the requirement about the work the author does, which is a bit off.

If it's not testable, I think making it non-normative is better. e.g. s/should work/are encouraged/

Copy link
Member

Choose a reason for hiding this comment

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

I don't see any remaining normative text in the section we're talking about, so I think this is resolved?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This paragraph is still there and still says "authors should work to ensure".
Perhaps we could just change it to "authors are encouraged"?

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 @@ -59218,7 +59298,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 @@ -59260,22 +59341,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 @@ -76187,9 +76278,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 @@ -76805,11 +76896,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