whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.03k stars 2.62k forks source link

Api to get prev/next focusable element #7924

Open jimmywarting opened 2 years ago

jimmywarting commented 2 years ago

A common senario is to have the possibility to navigate a datagrid, treeview and other things with keyboard. But something that's a bit annoying is finding the prev / next element that is visible & focusable. some element in between could be hidden (like a column, row or a collapsed treeview)

if you have a treeview like the one below; and you have your focus on the file.txt and wants to focus one the next element below when pressing down arrow key, then we have to traverse the tree upwards (b/c it was the last child) and find the next sibling (if any exist)

when I wrote this hole keyboard navigation with left/right/up/down for this collapsable treeview then it quickly become a bunch of code for something that is just as simple as just focusing the targeted element with just tab & shift+tab it would have made everything just a hole lot simpler if i could have some access to all the elements tab index

Something like document.activeElement.nextFocusable?.focus() and document.activeElement.prevFocusable?.focus() that maps to tab and shift+tab would have been nice to have

domenic commented 2 years ago

Somewhat of a dupe of https://github.com/whatwg/html/issues/4784 , although this one is more use-case focused instead of promoting a separate repository's worth of proposal.

jimmywarting commented 2 years ago

4784 sounds interesting. It would also solve my use case. But it was quite a lot locking at it now. #7054 is also another thing that is interesting.

All i really need is to somewhat emulate how tab and shift tab works. That's all i really need right now

Could close this in favor of one of those two issue if you like

deltragon commented 2 years ago

jquery UI has a :focusable selector. IIRC, it is broken in certain edge cases, but would something like this (when used with node.querySelectorAll()) be helpful/more general here?

jimmywarting commented 2 years ago

Another problem i had when determinating if a details elements inside of another detail was visible with get bounding box was that the width and height was still the old value and wasn't set to zero

jimmyfrasche commented 2 years ago

Even if there were a way to access the next/previous activeElement there would still be a lot of special cases to handle and cases where you couldn't do the same thing as a user hitting tab/shift+tab, like stepping out of an iframe into the enclosing document or out of the window into the browser chrome.

Maybe there needs to be an imperative API that tells the browser to act as if the user pressed tab/shift+tab and then do whatever needs to be done. Something like:

document.moveFocus(options = {
  preventScroll: false,
  direction: "forward",
})

(maybe it needs to be on window instead of document—not sure)

I'm not sure how it would extend for focus groups as I haven't followed that in depth. Possibly an option to "hit right/left arrow" instead of tab/shift+tab iff document.activeElement is in a focus group.

deltragon commented 2 years ago

IMO websites should never be able to access the browser chrome in any way. If a website moved my focus to browser UI automatically, I would be very confused. Additionally, this means that to do anything useful, the website would need to assume details about how the browser chrome is layed out - which will break not just between different browsers, but also with updates.

Similarly for iframes, it seems like a security risk to allow a child iframe to move the focus of the parent, or a parent iframe to move the focus inside a cross-origin iframe. A website should already be able to access the dom of a same-origin iframe normally anyways.

jimmyfrasche commented 2 years ago

I didn't say it should have any access to anything once the focus moved. It wouldn't be able to access anything about the chrome or other iframes. if focus ends up outside the page that just means focus isn't in the page anymore.

This is for handling focus leaving a component and if the component's the last thing on the page focus should behave the same way it would for something built in