Skip to content
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

Mechanism for setting the tabindex focus flag without sprouting tabindex attribute? #762

Open
alice opened this issue Aug 22, 2018 · 89 comments · May be fixed by whatwg/html#5120
Open

Mechanism for setting the tabindex focus flag without sprouting tabindex attribute? #762

alice opened this issue Aug 22, 2018 · 89 comments · May be fixed by whatwg/html#5120

Comments

@alice
Copy link
Member

alice commented Aug 22, 2018

Certain HTML elements are focusable without having an explicit tabindex attribute:

  • a elements that have an href attribute
  • link elements that have an href attribute
  • button elements
  • input elements whose type attribute are not in the Hidden state
  • select elements
  • textarea elements
  • summary elements that are the first summary element child of a details element

It would be nice if custom elements could also opt in to being focusable without having to sprout a tabindex attribute - such that if page authors removed the tabindex attribute, the element was still focusable.

It seems like this would be something that might fit in with whatever new API comes out of #758.

@domenic
Copy link
Collaborator

domenic commented Aug 22, 2018

Strong +1.

Do you think it's worth exposing both of tabindex's capabilities here, or just one? They are:

  • tabindex >=0 : reachable by sequential focus navigation, and also focusable in other ways (e.g. by the mouse or by .focus())
  • tabindex = -1: generally not reachable by sequential focus navigation, but focusable in other ways. (May also be reachable by sequential focus navigation in some circumstances; see the spec's "One valid reason to ignore the requirement"...)

I think there are common built-in elements whose behavior falls into each of these categories, although it may be OS dependent.

@bkardell
Copy link

+1 and I would like to see both 😀

@alice
Copy link
Member Author

alice commented Aug 22, 2018

In all honesty, I've never understood why tabindex = -1 is a thing, other than for excluding things from the tab order - i.e. why aren't all elements programmatically focusable? What do we gain from focus() sometimes being a no-op? Who is out here trying to call focus() on a <div> and hoping it ... fails?

But that aside, I guess allowing focusable things to also opt out of the tab order is probably useful for managing focus within complex components.

@annevk
Copy link
Collaborator

annevk commented Aug 22, 2018

@alice tabindex="-1" also affects what you can click and will get a focus ring, iirc.

@alice
Copy link
Member Author

alice commented Aug 22, 2018

@annevk True, although I've seen that cause more undesirable behaviour than desirable.

@rniwa
Copy link
Collaborator

rniwa commented Aug 24, 2018

Whatever mechanism we use for tabindex should be flexible enough to default ARIA role & other ARIA attributes as well.

@alice
Copy link
Member Author

alice commented Aug 24, 2018

@rniwa Agreed, I'm hoping all of the use cases mentioned in #758, plus this one, can share the same mechanism.

@SiTaggart
Copy link

Wouldn't it be great if an element became focusable just by setting its role to something that is known to be an interactive element as per the ARIA spec. Just like a button is implicitly focusable, if I set the role of an element to be a button, I would love for the browser to just take care of it for me.

@alice
Copy link
Member Author

alice commented Aug 26, 2018

I seem to recall ARIA affecting behaviour in that way was a deal breaker in the past - ARIA's contract is that it only affects accessibility tree computation.

(Edited to add:)
The reasoning being that if ARIA affected behaviour, it might discourage authors from using it.

@chaals
Copy link
Contributor

chaals commented Oct 26, 2018

Discussion at TPAC: We should keep in mind the concern that platform conventions differ, so we don't want to be in a position where authors can't match behaviour of the platform they are on. Consider a mode where you match some other element's behaviour...

@alice
Copy link
Member Author

alice commented Oct 26, 2018

https://allyjs.io/data-tables/focusable.html

@tkent-google
Copy link
Contributor

A possible API is:

interface ElementIntenals {
  attribute boolean defaultTabindexFocusFlag;
}

If the tabindex content attribute of the target element is omitted or the attribute value is not parsable, 'tabindex focus flag' is initialized with defaultTabindexFocusFlag value.

@domenic
Copy link
Collaborator

domenic commented Apr 17, 2019

@tkent-google I think that is the simplest design that could work. (Although I would change the name to be something less spec-focused and more intelligible to authors, but that doesn't matter for now.)

However, the above discussion revealed a few other possibilities:

What do you think of these considerations? Maybe they are overcomplicating things, and we should just go with the simple boolean version.

@tkent-google
Copy link
Contributor

We have two categories of focusable elements in Chrome:

  • Elements which supports complex keyboard interaction while it's focused
    Text-field INPUTs, TEXTAREA, SELECT, contenteditable
    They are "Text boxes and lists" in macOS Full Keyboard Access setting.
    :focus-visible and :focus have same behavior.

  • Elements which supports simple keyboard interaction. e.g. Spacebar works as click.
    Buttons and links
    They are skipped in sequential focus navigation if Full Keyboard Access setting is "Text boxes and lists only".
    :focus-visible doesn't match to them if they are focused by mouse click.

If we support only these two categories, we should add a boolean flag like needsComplexKeyboardInteraction.
Do we want to support a behavior other than these two categories?

@annevk
Copy link
Collaborator

annevk commented Apr 18, 2019

Probably, see whatwg/html#938 (comment) onward for some discussion on this. It'd be good to first sort this out for existing features though, before exposing it to the world.

@domenic
Copy link
Collaborator

domenic commented Apr 18, 2019

Well, there's a third category, right? Elements like div, which are not focusable (without explicitly setting tabindex). So I think a tri-state is necessary if we want to support the range of capabilities.

And, of those three categories, which does <div tabindex="0"> fall into? What about <div tabindex="-1">?

The big question is whether those three (?) categories of Chrome's are matched by other browsers. I am hopeful they kind of are, and the thread @annevk links to has some details I should re-read. We should try to confirm.

It would be great if we could figure out the total set of behaviors that browsers want to expose. Then we could codify that model in the spec, better than the current text, and expose it to custom elements. I don't think that'll be too hard...

@tkent-google
Copy link
Contributor

@domenic, yes, there are three categories if we include non-focusable. I meant categories in default focusable elements.

In Safari, the second category in my comment is not mouse-focusable even if Full Keyboard Access setting is "All controls".
Behavior of overflowed elements and <video controls> may be implementation bugs which we should fix.

tabindex attribute should override the default focus behavior, right?

@domenic
Copy link
Collaborator

domenic commented Apr 19, 2019

In Safari, the second category in my comment is not mouse-focusable even if Full Keyboard Access setting is "All controls".

Interesting! Maybe it's a bit early to start guessing at APIs, but this could point toward a setting like matchFocusBehaviorOf: which is allowed to be one of "input", "button", "div". Or maybe focusBehavior: "text entry", "clickable", "none" to be more abstract.

tabindex attribute should override the default focus behavior, right?

Yep! I am just hoping that div-with-tabindex falls into those two categories, not some new category.

@rniwa
Copy link
Collaborator

rniwa commented May 2, 2019

I think the challenge here is designing this API to be future proof. We don't want to hard code what's exactly needed for existing platforms because that'd limit future platform that we can't even imagine exist today.

@domenic
Copy link
Collaborator

domenic commented May 2, 2019

Yeah, agreed. I think we can do that by using an enum instead of a boolean (and it looks like there will be 3+ options anyway). We can then expand that as needed.

Would you be able to confirm the categories of behaviors currently present in Safari?

@rniwa
Copy link
Collaborator

rniwa commented May 3, 2019

Safari's behavior is that by default only form controls are tab focusable. Option + tab would focus every element that's focusable by default like link elements. Separately, every non-editable form element like buttons or input[type=submit] is not mouse focusable. In order to correctly describe WebKit's behavior, we'd need to be able to differentiate four states:

  • Editable form controls - tab & mouse focusable
  • Non-editable form controls - tab focusable but not mouse focusable
  • Links - option+tab focusable and mouse focusable
  • Everything else - not tab or option+tab focusable by default

Note that the user can override the behavior of tab key to be more like option+tab in Safari's preferences.

we can do that by using an enum instead of a boolean

I think enum value is problematic because that would mean that whenever a new platform shows up, or the platform convention changes, websites may need to adopt the change. Also, I don't think hard-coding the list of things Safari do today to the web platform is a good idea either. Specifying relative to builtin elements is an interesting idea although it's hard to differentiate editable input from non-editable input but perhaps input is an odd case due to its behavior completely changing based on type attribute.

@tkent-google
Copy link
Contributor

TPAC 2019 discussion: https://www.w3.org/2019/09/17-components-minutes.html#item07

It mentioned possibility of borrowing concepts from ARIA. Does it mean using ARIA roles as high-level concepts?

@alice
Copy link
Member Author

alice commented Oct 16, 2019

Apologies for the long comment. Hopefully it's at least clear.

I think there are three fundamental states for focusability: an element is

  • not focusable (a plain <div>), or it is
  • programmatically focusable* (tabindex=-1), or it is
  • user focusable (<button>, <textarea>, <a href> <input type=*>, etc).

I think the logic behind Safari's choices around how a user may focus certain elements is something along the lines of:

  • Everything that is user-focusable is mouse-focusable by default (exception below)
  • Editable form controls are tab focusable to enable rapid form filling from the keyboard
  • Non-editable form controls are tab focusable because they are form controls, but not mouse focusable because they aren't interactive in practice
  • Links (and <button>) are not keyboard focusable by default (but users may opt in) because for mixed-modality users filling out a form rapidly they are more likely to get in the way if included in the tab order (e.g. "more info" or "reset password" links when you mean to navigate to the submit button)
  • In addition, elements with tabindex=0, plus some other elements like <details>, <audio controls> and <video controls> are also always tab-focusable in Safari.

I think that comes down to three classes for built-in "user focusable" elements:

  • mouse focusable, always tab focusable (form controls, things with tabindex=0, etc)
  • mouse focusable, opt-in tab focusable (links, buttons)
  • not mouse focusable but tab focusable: non-editable form controls

If we ruled out wanting to emulate non-editable form control behaviour**, that would come down to whether something is:

  • always tab-focusable (tabindex=0), or
  • UA decides (link, buttons - always focusable in some UAs, selectively focusable in others)

So that comes down to four categories:

  • unfocusable
  • programmatically focusable
  • user focusable: UA decides*** about tabbable
  • user focusable: always tabbable

That seems both simpler and more robust than using ARIA roles, in particular since we don't yet have parity between ARIA roles and HTML elements (there's no video role, for example).


* in my experience, having an element with tabindex=-1 be focused on click causes many more problems than it solves, so I'm explicitly ignoring that behaviour here

** it would be straightforward enough to just add a click listener with preventDefault(), for example

*** a UA could also use other signals, such as form participation, to decide whether this should be treated as "always focusable"

@rniwa
Copy link
Collaborator

rniwa commented Mar 20, 2020

On macOS, with full keyboard access enabled, in many cases, each such interactive part should be in the tab order. Without full keyboard access, it shouldn't be. At the very least, that's true for tabs and tree views.

I just tested it on the macOS settings app, and tabs are one tab stop in that context. Arrow keys choose between the different tabs (and move the focus indicator).

Screen Shot 2020-03-09 at 6 59 20 pm

I think you have this checkbox turned on, which is off by default. This is what "full keyboard access" Maciej was talking about in his reply:
Screen Shot 2020-03-19 at 10 10 20 PM

@othermaciej
Copy link

othermaciej commented Mar 20, 2020

The disconnect is that when I referred to tabs I meant window-level tabs, like this:

Screen Shot 2020-03-09 at 11 26 20 PM

For tabs like that, each is always in the tab focus order.

What Alice screenshotted is a "segmented control" but may also reasonable be called tabs.

I can confirm that it has the behavior she describes; it's a single stop in the tab order, it draws a focus ring around exactly one item, and it moves through the items with arrow keys. A similar thing is true of radio button groups in native UI; only the currently active radio button is in the tab order. Or, looked at another way, a radio button isn't a control, a radio button group is. Indeed, the segmented control is sort of an alternate presentation of a radio button group. WebKit even replicates this behavior of radio button groups in HTML when "Use keyboard navigation to move focus between controls" is enabled.

I'm not sure this pattern is best represented. Under full keyboard access, radio buttons are individual elements that are always click-focusable, but, at least on macOS (not sure how this works on Windows), only the active one is in the tab cycle. It's reasonable for other elements intended to be part of a group to have this behavior. Less clear (to me) whether there is a need to not be click focusable in such a scenario.

@rniwa
Copy link
Collaborator

rniwa commented Mar 20, 2020

What Alice screenshotted is a "segmented control" but may also reasonable be called tabs.

I can confirm that it has the behavior she describes; it's a single stop in the tab order, it draws a focus ring around exactly one item, and it moves through the items with arrow keys. A similar thing is true of radio button groups in native UI

I'm pretty certain that behavior only exists if "Use keyboard navigation to move focus between controls" in (somewhat misleadingly labeled) Shortcut section of Keyboard in System Preferences is checked (I've confirmed this on 10.15.3 19D76). By default, you can't press tab key to focus any section title in Keyboard or any of the checkboxes.

@cookiecrook
Copy link

@othermaciej wrote:

List boxes don't give individual focus to their elements, the list box as a whole is the only thing to get focus.

@alice replied

I just tested it on the macOS settings app, and tabs are one tab stop in that context. Arrow keys choose between the different tabs (and move the focus indicator).

If I understand the distinctions you're each making, you two are agreement on the relevant parts.

Maciej mentioned that managed focus AppKit controls don't focus the sub-views, per se. But AppKit does style the sub-views and vends enough information for AT to understand the relationship... Somewhat similar to the concept of aria-activedescendant

Alice mentioned that more web controls use the other managed focus technique: roving/roaming tabindex. (There's a demo video of r–ing tabindex in Example 2 of this 2014 WebKit post). Each technique is useful.

In both cases, on Web or native platforms, the user experiences the same end result: one tab stop, with other non-Tab keypresses modifying the widget's sub-level focus or visible focus indicator. The distinction of whether the container or the sub-view gets actual focus feels like a implementation detail of the platform.

@cookiecrook
Copy link

Aside: should elements with @draggable get a default focus behavior, too?

@cookiecrook
Copy link

Attributes that affect focusability (or should):

  • tabindex
  • href
  • disabled
  • contenteditable
  • draggable?

Feel free to edit this comment to add any I overlooked.

@domenic
Copy link
Collaborator

domenic commented Mar 31, 2020

I'm not sure what the latest is in this thread and proposal, but I'll drop a note that the eventual proposal should be sure to make the resulting controls interactive content. As whatwg/html#5414 points out this has an effect on <label> behavior.

@alex-shevchenko
Copy link

Perhaps autofocus should also be considered within this issue, to take into account the case when FACE is upgraded?

@alice
Copy link
Member Author

alice commented May 4, 2020

I think they might be orthogonal, but someone else may be able to correct me - i.e. autofocus may be used on any element, and if the element is not a focusable area at the time the "flush autofocus candidates" algorithm is run, and "getting the focusable area" returns no result, the element simply isn't focused.

@alex-shevchenko
Copy link

Right, but it means that when the new way to make an element focused, is provided according to this discussion, it will not work with autofocus (or even worth, it will provide intermittent results).

It seems reasonable to update autofocus spec so that the algorithm is also triggered when custom element is upgraded.

@alice
Copy link
Member Author

alice commented May 5, 2020

I see - on document load, the element may not yet be focusable, since it hasn't yet upgraded.

@vadimkantorov
Copy link

vadimkantorov commented Jun 15, 2020

I've also stumbled upon on "always tab-focusable audio controls in Chrome regardless of tabindex". Had to do a JS workaround :( For some fast tab-navigation scenarios 6 audio controls being tabbed-through destroys the tab navigation usecase, especially when audio isn't supposed to be played often and tab navigation is supposed to be used often (in some crowd-sourcing scenarios)

@cookiecrook
Copy link

cookiecrook commented Sep 8, 2020

From this gist, @alice wrote:

I think we can get away with two states, with several caveats.

The states would be:

focusable (or auto, or...)
default (or unfocusable, or...)

The caveats:

unfocusable custom elements would still be programmatically focusable.

So, custom elements set as unfocusable would not be in the tab order, but would still achieve focus if the author called the .focus() method on the custom element. Correct?

Safari would need to determine click/sequential focusability of focusable elements based on ElementInternals role.

Another gist gives an example of using these two states to manage focus within a complex custom element.

@cookiecrook
Copy link

cookiecrook commented Sep 9, 2020

Safari would need to determine click/sequential focusability of focusable elements based on ElementInternals role.

"Safari would need to" may not be true. I see at least two options:

  1. Safari could (No opinion yet on whether it should) use the focusable state plus role as a way to determine whether elements appeared by default in the tab order, based on the existing platform keyboard behavior as modified by system and browser settings.
  • This would be an example of accessibility-related code (the role) resulting in changed behavior (follow-up "slippery slope" argument)
  • Ryosuke brought up an implementation concern (re: firstResponder) that achieving focus (even programmatic-only) would be incompatible with the unfocusable state. I'll let him explain that concern in further detail.
  • There's the interop risk that Safari would be doing something different that other browsers. We already have this interop challenge with native controls like <button> but it's always been so. We'd be adding a new interop problem here.
  1. For custom elements, Safari could treat them like it does ARIA elements (E.g. <div role="button" tabindex="0">), where focusability and tab order is controlled by the focusable/unfocusable state (role ignored), and programmatic .focus() calls would be ignored on non-focusable elements.
  • The primary downside of option 2 is that this would formalize an API/behavior that ignores the platform convention of Mac/Safari, where users expect certain element types to be tab-focusable or not based on their user settings.

@cookiecrook
Copy link

@alice wrote:

unfocusable custom elements would still be programmatically focusable.

Above you mentioned roaming/roving tabindex as the primary justification for programmatic focus, but most of the examples I've seen toggle the state of those sub-controls between tabindex="0" and tabindex="-1" effectively making them focusable and non-focusable. The portion of the control gets focused is always made focusable at the same time the author calls .focus(), right?

If so, maybe it's okay to force the author to make a custom element focusable before calling .focus()... Putting this limitation on custom elements may bring us back to a simpler boolean state: focusable or not.

@cookiecrook
Copy link

cookiecrook commented Sep 9, 2020

In chrome://settings/appearance, there is a setting that is similar to the Mac Safari setting, called: "Pressing Tab on a webpage highlights links, as well as form fields." @alice, would your proposal to have Safari adjust tab-focus by role also apply to Chrome in this context?

Screen shot of Chrome settings checkbox labeled: Pressing Tab on a webpage highlights links, as well as form fields.

@rniwa
Copy link
Collaborator

rniwa commented Sep 9, 2020

From this gist, @alice wrote:

I think we can get away with two states, with several caveats.
The states would be:
focusable (or auto, or...)
default (or unfocusable, or...)
The caveats:
unfocusable custom elements would still be programmatically focusable.

So, custom elements set as unfocusable would not be in the tab order, but would still achieve focus if the author called the .focus() method on the custom element. Correct?

Making custom elements always programmatically focusable doesn't seem like a backwards compatible change to me. During our work to make Safari to iPad load desktop sites, we encountered numerous websites including Microsoft Office 365 that move focus inadvertently(?) to multiple elements before the correct element is focused. Making previously non-programatically focusable element always programmatically focusable has a risk that it would make previously no-op focus() call move the focus to the context object and blur the previously focused element. This can result in a wrong element having the focus. We need to come up with some way to mitigate this backwards compatibility risk. I don't that's the kind of compatibility risk we want to take given how many tricky-to-diagnose bugs we've encountered in this area especially in conjunction with iOS's software keyboard & focus scrolling behavior.

@rniwa
Copy link
Collaborator

rniwa commented Sep 9, 2020

Here's my attempt of summarizing the discussions we've had so far.

In 2018 TPAC, we concluded that we wanted to respect platform differences. One approach considered is adding the ability to match other element's behavior. One of the simplest approach propsoed by tkent-google is to add a signle boolean like defaultTabindexFocusFlag in ElementIntenals. Domenic's counter propsal is that we may need tri-state to capture click vs. keyboard focusability. I pointed out that Safari differentiates editable and non-editable form contorls as well as hyper links so we may need four different states along with a point that listing exactly what Safari needs won't be future proof.

In 2019 TPAC, we discussed the idea of using ARIA role as a way of detecting which element is focusable. Alice proposed that if we ignored non-editable form control behavior, we can narrow the cateogires down to four: unfocusable, programatically focusable, user focusable but keyboard focusable depending on UA, and always keyboard focusable. Maciej then pointed out that Safari doesn't include all form controls in the tab order; only editable ones like textarea is included. Tkent then brings up that at 2019 TPAC, we came to a conseusus to introduce a high level categories and sgugests: unfocusable, general, and control. There was some bikeshedding.

After more bikeshedding, Alice suggested that we can have four categories: unfocusable, programmatically focusable, user focusable but UA dependent for tab order, and user focusable and always in tab order. Maciej points out that if we split "accepts text input" (i.e. editability) into its own property, then we need two states but suggested that tri-state is simpler: text-input-control, control, non-control. Alice then suggests that we can have "sequential" and "auto" instead where the former means always in tab-order and the latter means UA decides. In Maciej also questioned why we need programatic focusability separately and Alice replies that some complex widgets would need this capability to control which sub-components would need focusing. Maciej mentions that leaving UA to decide what is in tab order will result in developers writing components that don't play nicely with platform conventions. Then there are some macOS specific UI discussions.

More recently, Domenic pointed out that this propopsal needs to also make the focusable custom element interactive content as it affects label element's behavior. Then Alex pointed out that we may also need to trigger autofocus once custom elements are upgraded.

@alice
Copy link
Member Author

alice commented Sep 9, 2020

@alice, would your proposal to have Safari adjust tab-focus by role also apply to Chrome in this context?

Wow, TIL.

Yes, I agree Chrome should be consistent with whatever Safari decides (i.e. treating Custom Elements the same for focus as either <div tabindex=0>, or treating them the same as built-in elements with the same role).

@alice
Copy link
Member Author

alice commented Sep 9, 2020

maybe it's okay to force the author to make a custom element focusable before calling .focus()... Putting this limitation on custom elements may bring us back to a simpler boolean state: focusable or not.

This is definitely worth experimenting with; it would avoid the issues @rniwa mentioned.

I had a play with doing this with tabindex: https://codepen.io/sundress/full/oNxqYaR

I do seem to recall that there were some potential issues with this, but so far I can't remember what they may have been.

I asked a colleague who works in front-end development, and they noted that not having a programmatic focus state means there is extra (and thus potentially error-prone) work when you want to move focus to something but not have it remain user-focusable after focus moves away. Maybe the solution there is an option to focus() to override the focusability bit?

@cookiecrook
Copy link

cookiecrook commented Sep 14, 2020

@alice wrote:

I asked a colleague who works in front-end development, and they noted that not having a programmatic focus state means there is extra (and thus potentially error-prone) work when you want to move focus to something but not have it remain user-focusable after focus moves away. Maybe the solution there is an option to focus() to override the focusability bit?

How would that be different than making all custom elements always programmatically focusable? Wouldn't it result in the same problems @rniwa mentioned on the Microsoft Office 365 web app?

@alice
Copy link
Member Author

alice commented Sep 15, 2020

How would that be different than making all custom elements always programmatically focusable?

I meant to suggest that you would have to opt-in to overriding the focusability bit, e.g. focus({force: true});

If you're depending on focus() being a no-op for non-focusable elements, you wouldn't use that option. Also, it wouldn't cause existing code to suddenly change behaviour.

While we're exploring options, we should keep our use cases in mind as well. I can really only think of two use cases for tabindex=-1 behaviour:

  1. Managing focus within a complex widget, typically a collection of similar sub-elements of which one is in the focus order (i.e. 'roving tabindex'). In this case, we would want several things to happen at once:
    • focus the sub-element in question
    • add the sub-element to the focus order
    • remove all other sub-elements from the focus order
  2. Moving the focus navigation start point and AT point of regard to a container element, for skip links and pieces of transient UI like menus and modals. In this case, we aren't expecting any kind of keyboard interaction with the element itself, nor do we want it to remain in the tab order.

Are there any other use cases I've missed?

@JanMiksovsky
Copy link

JanMiksovsky commented Sep 17, 2020

We discussed this at this week's web component meeting.

@rniwa put forth an update to Apple's tri-state proposal referenced in his summary above. In this, elementInternals would have a focusMode property with three values:

  1. "none" (not focusable)
  2. A value indicating that the element is focusable and edits text
  3. A value indicating that element is focusable but does not edit text

The difference between #2 and #3 would let Safari provide its distinct UI behavior in which focus skips components in category #3 by default.

Various people expressed questions about how developers would distinguish between categories #2 and #3, particularly for new types of components that have no analogues among the existing HTML elements. E.g., one class of interesting components are list boxes and other elements that support typeahead (type some characters to select an item that begins with those characters). Do those components edit text?

Given that Apple is the entity making the distinction, the suggestion was that Apple provide guidelines about how it would categorize various categories of elements whose focusability might conceivably be in question. Those guidelines could then be incorporated into the documentation of the focusMode enum so that developers could make a reasonable determination on their own as to which value best reflected the component's use.

One concern raised with this proposal is that, by default, WebKit does not focus components in category #2 — e.g., form controls like radio buttons — when the user clicks on them. That behavior might confuse or cause problems for a web developer using that #2 focusMode value for their component.

@domenic
Copy link
Collaborator

domenic commented Sep 17, 2020

FWIW I continue to be excited about tri-state proposals that let custom elements continue to capture the same capabilities as built-in elements. And I am glad that this is orthogonal to other pieces of state (e.g., role). I am willing to help with updating @tkent-google's tri-state pull request (whatwg/html#5120) with appropriate new names and documentation, once folks have figured them out.

@alice
Copy link
Member Author

alice commented Oct 7, 2020

I'd like to continue the discussion about programmatic focus, just to make sure we aren't missing any critical functionality by excluding it.

I'd be interested to hear from @JanMiksovsky or any other web component developers whether the use cases I listed in #762 (comment) are the full range of what tabindex=-1 is used for in practice.

For (1) above, perhaps a worked example might help with intuition.

Say you're developing a date picker widget. When the date grid dialog is open, you'd want to be able to programmatically move focus/selection among the days of the month shown, but only have the pre-selected month appear in the focus order.

Screen shot of the ARIA practices calendar widget example linked above, with the date picker dialog open

In this screenshot, the user had previously used the arrow keys to move focus/pre-selection to "1", and then used the tab key to move focus to the "previous month" button.

If the user uses the tab key to move the focus back to the calendar grid, the "1" cell will be focused again. If the user clicks on any of the other days, or uses the arrow keys to select an adjacent day, that day will be focused and pre-selected (the selection not being committed until the user activates the 'Ok' button).

I am interested in whether developers would tend to:

  • use tabindex to make the day elements programmatically/sequentially focusable as necessary, or
  • coordinate to make the "next" day element (e.g. "2", if the user had focused "1" and pressed the right arrow key) focusable "just in time", by giving the coordinating script access to each day's ElementInternals, or
  • miss a potential mechanism to have the day elements be made programmatically focusable via ElementInternals, so that you could call focus() without having to have access to the ElementInternals or use tabindex to make the element focusable first.

@clshortfuse
Copy link

clshortfuse commented Aug 30, 2022

The problem I'm having is wrapping a native element (eg: <button> or <input>) in a web component and not duplicating the roles.

<x-toolbar role=toolbar>
  <x-button role=none tabindex=0>
    #shadow
      <button tabindex=0>Button 1</button>
  </x-button>
  <x-button role=none tabindex=-1>
    #shadow
      <button tabindex=-1>Button 2</button>
  </x-button>
</x-toolbar>

This works fine and Chrome and will show the AOM tree correctly. <x-button> will use delegatesFocus and properly focus the <button> But Firefox doesn't like it (warnings). Also, I'm not supposed to mix [tabindex] with [role=none]. But the problem I'm having is: how do I tell x-toolbar that x-button is a focusable element and how should x-toolbar manage roving tabindex of its children?

I created another setup, but it requires now rewrite my mostly universal roving tabindex code for a custom attribute (x-tabindex):

<x-listbox role=toolbar>
  <x-listbox-option role=none x-tabindex=0>
    #shadow
        <input type=checkbox role=option tabindex=0 name=option1>
  </x-listbox-option>
  <x-listbox-option role=none x-tabindex=-1>
    #shadow
        <input type=checkbox role=option tabindex=-1 name=option2>
  </x-listbox-option>
</x-listbox>

Who's in the right here? Chrome or Firefox? Firefox doesn't seem to like a focusable element with role=none even with the custom x-tabindex attribute. Do I move forward with tabindex + delegatesFocus (Chrome) or start making general focusable elements in light DOM that don't use any semantic HTML in shadowDOM (FireFox)? I'll test these mechanics in Safari, but right now it's pretty concerning to not have a single solution for semantic+ARIA+tabindex.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

15 participants