[w3c/webcomponents] Focus delegation from shadow host should not behave like sequential focus navigation (#830)

A brief summary of focus to help understand the issue:
* Focusing on an element can be done through three methods: sequential, click, and programmatical. They differ in a number of ways, but for this issue we will only need to know the differences related to the `tabindex` value.
  * Sequential focus navigation (Moving focus with tab key) skips elements with negative `tabindex` value
 * Sequential focus navigation also prioritizes elements whose `tabindex` value is non-zero, in increasing order. So it will move the focus to all element with `tabindex` value of 1, and then all element with `tabindex` value of 2, ... and so on, and finally move the focus to elements with `tabindex` value of 0 last. 
  * Click focus (clicking on an element) and programmatic focus (calling `focus()` on an element) will focus on elements even if their tabindex value is negative
* When attaching a shadow root to a host, we can set its `delegateFocus` value to true, so that the host will delegate focus.
* When a host that delegats focus is the target of focus (with any method) it will not focus on the host, but instead move/delegate the focus to one of the element in its shadow root's tree/scope.

While we were trying to move the delegatesFocus spec to the HTML spec on https://github.com/whatwg/html/pull/4796, @domenic pointed out that the current behavior (which I think is only implemented in Chrome?) is quite weird: it uses sequential focus navigation even when the host gets focused with clicking on it or calling the `focus()` method on it.

Currently the delegation process finds the new focus target with sequential focus navigation, this means in this case:
 ```
<div #host>
  #shadowRoot delegatesFocus=true
   <div tabindex=-1>clickable</div>
   <div tabindex=0>sequentially focusable</div>
```
If we click/call `focus()` on the host, it will focus the "sequentially focusable" div instead. This is a bit weird because it's inconsistent with the method that initially makes us target the host in the first place.
**Proposal to change the behavior:**
If we click/call `focus()` on the host, we  should be as if we actually click/call `focus()`  on the first element that is click/programmatically focusable, even if it's not sequentially focusable - in this case the "clickable" div. Note that if we are focusing on the host through tabbing to it (sequential focus navigation), then we will use sequential focus navigation and skip elements with negative tabindex values.

Another point - the current behavior in Chrome also cares about tabindex value priority mentioned earlier. For example:
 ```
<div #host>
  #shadowRoot delegatesFocus=true
   <div tabindex=0>A</div>
   <div tabindex=1>B</div>
</div>
```
If we focus on #host, the "B" div will get focus.
**Proposal to change the behavior:**
Since we want to change the behavior of focus delegation to not be related to sequential focus navigation, we should probably remove the tabindex priority thing as well in this case. So we should always delegate focus to the first focusable area in DOM/composed-tree order - in this case the "A" div.

Since the sequential delegation behavior is already implemented in Chrome, there is a compatibility risk for changing to the proposed behavior. I predict this to be small and worth it for the change, but would love to hear from people who actually use this on whether this change makes sense and whether it's hard to move from the old behavior to the new one.

cc @rniwa @annevk @smaug---- and possible users of delegatesFocus that might be impacted @justinfagnani @muan? 

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/830

Received on Wednesday, 28 August 2019 14:05:51 UTC