This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 26669 - Bad design: autofocus attribute
Summary: Bad design: autofocus attribute
Status: RESOLVED WONTFIX
Alias: None
Product: WHATWG
Classification: Unclassified
Component: HTML (show other bugs)
Version: unspecified
Hardware: Other other
: P3 normal
Target Milestone: Unsorted
Assignee: Ian 'Hixie' Hickson
QA Contact: contributor
URL: http://www.whatwg.org/specs/web-apps/...
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-08-26 09:07 UTC by contributor
Modified: 2016-03-24 17:56 UTC (History)
4 users (show)

See Also:


Attachments

Description contributor 2014-08-26 09:07:20 UTC
Specification: http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html
Multipage: http://www.whatwg.org/C#autofocusing-a-form-control:-the-autofocus-attribute
Complete: http://www.whatwg.org/c#autofocusing-a-form-control:-the-autofocus-attribute
Referrer: http://www.whatwg.org/specs/web-apps/current-work/multipage/

Comment:
Bad design: autofocus attribute

Posted from: 77.181.225.21
User agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0
Comment 1 Axel Dahmen 2014-08-26 09:13:25 UTC
Very bad design:

"There must not be two elements with the same nearest ancestor autofocus scoping root element that both have the autofocus attribute specified."

For this constraint, a better design would have been to add the 'autofocus' attribute to a <form> element, or any other nearest ancestor autofocus scoping root element. That would easily and automatically have established a 1:[0,1] relation.

The current design resembles some HTML webpage implementations where programmers unnecessarily use checkboxes and ECMA script to just emulate simple radio buttons.
Comment 2 Ian 'Hixie' Hickson 2014-08-26 18:16:41 UTC
There can be two forms in an autofocus scoping root element.
There can be two elements with the same ID.

The problem with putting the autofocus attribute on autofocus scoping root elements is that it results in "action at a distance", which is often confusing to authors.
Comment 3 Axel Dahmen 2014-08-26 21:34:55 UTC
That'd make no difference.

The current specification is a reverse pointer, requiring application logic to find the matching nearest root element. If the autofocus attribute was applied to an autofocus scoping root element instead, then if that element got created, it would be using one of its descendants with a matching ID, given by the autofocus attribute's value.

If "action in a distance" would be confusing to web authors, then the <label> element would be, too.
Comment 4 Ian 'Hixie' Hickson 2014-08-27 21:03:09 UTC
I'm not sure I follow. What applications have to find the matching nearest root element?
Comment 5 Axel Dahmen 2014-08-29 12:29:10 UTC
Sorry for having been ambiuous here. I was talking about browser applications.

If I'd have to write an algorithm to interpret the autofocus attribute, then after performing all the required constraint checks, I'd have to find the matching root element in the tree in order to forward my id to it, so if the root element was displayed (e.g. <dialog>) it would automatically set focus to the current input object.

Apart from dropping the quite cumbersome constraint implementation that's only necessary when the autofocus attribute gets applied to any of the input elements (e.g. by ECMA script), this search can as easily be performed by the root element itself, searching its children for a matching element when it gets displayed and has an autofocus attribute (with a child element's ID as its value) applied to itself.

I personally wouldn't feel the autofocus attribute to be confusing when applied to a root element at all.
Comment 6 Ian 'Hixie' Hickson 2014-08-29 19:07:01 UTC
The browsers aren't required to implement the constraint checks. In fact they're required not to. Those constraints are on authors.

There are conformance requirements that apply to producers, for example authors and the documents they create, and there are conformance requirements that apply to consumers, for example Web browsers. They can be distinguished by what they are requiring: a requirement on a producer states what is allowed, while a requirement on a consumer states how software is to act.

For example, "the foo attribute's value must be a valid integer" is a requirement on producers, as it lays out the allowed values; in contrast, the requirement "the foo attribute's value must be parsed using the rules for parsing integers" is a requirement on consumers, as it describes how to process the content.

Requirements on producers have no bearing whatsoever on consumers.

Continuing the above example, a requirement stating that a particular attribute's value is constrained to being a valid integer emphatically does not imply anything about the requirements on consumers. It might be that the consumers are in fact required to treat the attribute as an opaque string, completely unaffected by whether the value conforms to the requirements or not. It might be (as in the previous example) that the consumers are required to parse the value using specific rules that define how invalid (non-numeric in this case) values are to be processed.

The only relevant requirement on browsers, for autofocus, is the steps that follow "When an element with the autofocus attribute specified is inserted into a document, user agents should run the following steps". Note that those steps don't involve any sort of crawling of the DOM at all. They just focus the element straight away.
Comment 7 Ian 'Hixie' Hickson 2014-09-18 17:29:43 UTC
Closing per comment 6. If, given comment 6, there is still a spec issue here, please don't hesitate to reopen the bug. Thanks!
Comment 8 Axel Dahmen 2014-10-03 16:20:42 UTC
OK, I see... The point "Note that those steps don't involve any sort of crawling of the DOM at all." seems very valid to me.

Yet, I see problems arising when this attribute is added to ECMAScript IDL.

Even if the HTML interpreter wouldn't check constraints, the ECMAScript DOM would (necessarily).


What about dynamic scenarios? Scenarios where forms and dialogs are present in the DOM, yet hidden until necessary?

What about autofocus when the corresponding input element gets disabled? Is the uniqueness constraint valid at all in the end?

Wouldn't it be feasible to allow to set the autofocus to all input elements, without a production constraint like "There must not be two elements with the same nearest ancestor autofocus scoping root element that both have the autofocus attribute specified." -- If so, the first non-disabled element should then be chosen for autofocus when a form/dialog gets displayed.
Comment 9 Ian 'Hixie' Hickson 2014-10-11 00:26:57 UTC
The only time autofocus would involve scrolling the DOM is during dialog display, but as far as I can tell that's a trivial one-time cost in practice.

(In reply to Axel Dahmen from comment #8)
> 
> Wouldn't it be feasible to allow to set the autofocus to all input elements,
> without a production constraint like "There must not be two elements with
> the same nearest ancestor autofocus scoping root element that both have the
> autofocus attribute specified." -- If so, the first non-disabled element
> should then be chosen for autofocus when a form/dialog gets displayed.

What's the point of setting autofocus on an element if it's not going to be focused? Surely that would just be indicative of an authoring error.
Comment 10 Axel Dahmen 2014-10-11 03:07:19 UTC
Not necessarily.

Both, CSS and JavaScript can hide and/or disable an input element.

So it would not make sense to have the autofocus attribute just added to a single element that might be disabled or hidden by a stylesheet or JavaScript.

Instead it would make sense to have the autofocus attribute applied a number of candidate input elements, willing to take focus if they are both visible and enabled.

In order to set focus to an input element the production environment should skip all input elements which are either disabled or invisible and use the first element being (a) visible, (b) enabled, and (c) has the autofocus attribute applied.

Here's an example:

<form onload="document.getElementById('customerID').disabled = !document.getElementById('customerID').value;">
  <ul>
    <li>Customer No.:
      <input type="text" id="customerID" autofocus="autofocus" />
    </li>

    <li>Customer Name:
      <input type="text" id="customerName" autofocus="autofocus" />
    </li>

    <li>Customer Address:
      <input type="text" id="customerAddress" />
    </li>
  </ul>
</form>
Comment 11 Ian 'Hixie' Hickson 2014-10-13 22:24:35 UTC
The script that disables the control can also set the autofocus="" attribute.
Comment 12 Axel Dahmen 2014-10-14 09:28:02 UTC
... and style? What if style disables/hides a control, independant from the HTML content?
Comment 13 Ian 'Hixie' Hickson 2014-10-14 21:24:23 UTC
Style can't disable or hide the control. Style is optional; a user agent is always allowed to just ignore it. If one were to use style to disable a control, then one's app would be broken.
Comment 14 Axel Dahmen 2014-10-15 00:20:38 UTC
I don't understand... AFAIK, style can hide a control:

.registered input[type=text] {display: none;}



Plus, JavaScript frameworks, like Angular.js, provide features for initially displaying/hiding controls
(e.g.: http://www.w3schools.com/angular/angular_htmldom.asp)

These frameworks don't (and simply can't) address autofocus.

I still suggest the HTML should provide a number of candidates to choose from after applying a model on initial rendering when the form/dialog is displayed, so the first visible and enabled input element having the autofocus attribute applied will get focus.
Comment 15 Ian 'Hixie' Hickson 2014-10-15 18:29:11 UTC
".registered input[type=text] {display: none;}" just changes the rendering, it doesn't change the semantics. A browser that ignores CSS (which is perfectly valid behaviour) would still show the control.

If you want to hide the control semantically, you have to use hidden="", or remove the element from the DOM.
Comment 16 Axel Dahmen 2014-10-16 10:26:34 UTC
Which -still- from my perspective would result in a requirement for the autofocus attribute to be applicable to a number of elements within a parent.

What if a HTML page contained more than one single form? Then there might be several autofocus attributed elements, too. For instance, one within each form. Which one should be chosen to give focus to?

On the other hand, if you don't want to allow any DHTML thought in the design, then the "tabindex" attribute appears to be perfectly sufficient and renders the autofocus attribute redundant: The (first) input element with the smallest tabindex value != undefined becomes focus. If you want to give autofocus to another element, just apply different tabindex values to the input controls.

The tabindex design is decades old now and implies all the value the autofocus attribute likes to offer.
Comment 17 Ian 'Hixie' Hickson 2014-10-16 16:32:50 UTC
There's only allowed to be one element with autofocus="". The last element found with autofocus="" is the one that ends up having focus. This is all defined in the spec.

I don't see value in allowing authors to include redundant autofocus="" attributes. It would cause focus to move confusingly during a slow page load, and it's perfectly reasonable for a script to set the focus manually if it needs to dynamically decide what gets focus
Comment 18 Axel Dahmen 2014-10-17 11:03:34 UTC
Apparently you didn't read through my last message? There were two other thoughts I mentioned. Particularly concerning a possible redundancy of autofocus?
Comment 19 Ian 'Hixie' Hickson 2014-10-17 23:53:43 UTC
I don't understand the relevance of forms here.
tabindex="" doesn't help since by default the viewport is what gets the focus.

I just don't see what's wrong with autofocus="". It's implemented already, so if we are to change it we need a really good reason.
Comment 20 Axel Dahmen 2014-10-23 19:25:11 UTC
Strange... Sure the restriction do dialog was in the specs from the beginning? I can't remember that the autofocus attribute only applied to <dialog> parents.
Comment 21 Axel Dahmen 2014-10-26 13:44:47 UTC
Nonetheless, if there'd be at least one input element with tabindex != "", it's sufficient and concise to give focus to the input element with the lowest tabindex attribute value when opening a dialog.

Still no need to introduce autofocus attribute. It's redundant. The tabindex semantics perfectly fulfill this purpose, given the above definition.

As I wrote, the behaviour I'm describing is not an invention of mine but exists in GUI operating systems from the beginning (from the 80's), so it's a de facto standard behaviour.
Comment 22 Ian 'Hixie' Hickson 2014-11-26 22:27:27 UTC
Suppose your dialog looks like this:

   +-------------------------------------+
   | What would you like your _nickname_ |
   | to be on this game?                 |
   | [_________________________________] |
   |               [ Cancel ]  [ Start ] |
   +-------------------------------------+

...where "_nickname_" is a focusable hyperlink. You want the text field to have the focus when you show the dialog. You want the tab order to be text field -> start button -> cancel button -> nickname hyperlink.

If we have the autofocus="" attribute, you add the attribute and you're done. (Separately, your team of accessibility experts can come in and jiggle the tabindex="" attributes so that the cancel button comes after the start button.)

If we only have tabindex="", then you have to put a tabindex="" on all your elements, just so that the text field comes first. This is much more work. And then if you accessibility team comes in to fiddle with the tabindex="" attributes, they have to make sure they don't screw up the order and end up with a different node first.
Comment 23 Axel Dahmen 2014-11-27 11:28:47 UTC
Great example.

But there is no need to put a tabindex attribute to every element that can gain focus.

The algorithm would be just: "Give autofocus to the first element that's enabled, visible, has a tabindex set that's smaller or equal to all other elements being enabled, visible, has a tabindex set."

In jQuery terms the algorithm would be:



{
  var autoFocusElement;

  $("dialog [tabindex]:visible:enabled")
    .each(function (idx, elem)
           {if (!autoFocusElement || autoFocusElement.tabIndex > elem.tabIndex)
              autoFocusElement = elem;});

  if (autoFocusElement) autoFocusElement.focus();
}



So basically the autofocus attribute is redundant.
Comment 24 Axel Dahmen 2014-11-27 11:32:01 UTC
Forgot to add my conclusion regarding your comment #22 and my commen #23:

So it would be sufficient to just set tabIndex on one single element to have it gain autofocus:


<dialog>
  <input type="text" id="i1" />
  <input type="text" id="i2" tabIndex="1" /> <!-- = autofocus -->
  <input type="text" id="i3" />
<dialog>
Comment 25 Ian 'Hixie' Hickson 2014-12-01 05:44:22 UTC
Wouldn't that just make the tab order i2, i1, i3? It still needs to be i2, i3, i1.
Comment 26 Axel Dahmen 2014-12-02 16:21:01 UTC
I'm not sure. I couldn't find a specification on this.

Due to the dynamic enabled/visible situation of a document I would have assumed a browser application's internal tabbing sequence algorithm to be like the following:

(1)  Look for the focusable/visible/enabled element (= fveE) with highest
     tabindex set (= fveEHigh).

(2)  Look for the fveE with lowest tabindex set (= fveELow).

(3)  Find first fveE not having tabindex attribute set following fveEHigh
     (= fveEHighNext).

(4)  Backward-find first fveE not having tabindex attribute set proceeding
     fveEHigh (= fveEHighPrev).



So (provided all four element values are set for the sake of brevity here) pressing the tab key would result in the following algorithm to apply:

function onTabbing(element, goForward)
{
  if (element.tabIndex === null)
    if (goForward)
      {if (element === fveEHighPrev) fveELow.focus();
      else nextFveEWithoutTabIndexSet(element).focus();}
    else
      {if (element === fveEHighNext) fveEHigh.focus();
      else previousFveEWithoutTabIndexSet(element).focus();}
  else if (goForward)
      {if (element === fveEHigh) fveEHighNext.focus();
      else nextFveEWithTabIndexSet(element).focus();}
    else
      {if (element === fveELow) fveEHighPrevious.focus();
      else previousFveEWithTabIndexSet(element).focus();}
}



In that case, given:

  <input type="text" id="i1" />
  <input type="text" id="i2" tabIndex="2" />
  <input type="text" id="i3" tabIndex="1" /> <!-- = autofocus -->
  <input type="text" id="i4" />
  <input type="text" id="i5" />

the sequence would be: i3, i2, i4, i5, i1.
Comment 27 Ian 'Hixie' Hickson 2014-12-03 20:02:31 UTC
The spec leaves the relative order of the nodes without tabindex up to the browser, but I would find it very surprising if removing the nodes with tabindex="" set changed the relative order of the remaining nodes.

In any case, I feel this ignores the larger point, which is the maintenance issue raised in comment 22.
Comment 28 Anne 2016-03-24 17:56:40 UTC
We cannot change the design of this feature.