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

[css-display-4] Define how reading-flow interacts with focusable display: contents elements. #9230

Open
emilio opened this issue Aug 23, 2023 · 13 comments

Comments

@emilio
Copy link
Collaborator

emilio commented Aug 23, 2023

#8589 / #7387 (comment) propose new properties to alter the reading order of the items to follow the layout tree order, rather than the dom order.

However, that is in conflict with #2632 / mozilla/standards-positions#772, in the sense that there doesn't seem to be a good order for display: contents elements that are focusable in a visually-order container.

We need to sort out how these two proposals interact. What is the tab order of a display: contents element inside an element with non-auto reading-order?

cc @rachelandrew @tabatkins @fantasai @dbaron

@mfreed7
Copy link

mfreed7 commented May 15, 2024

I agree this is an issue. We (really @dizhang168) are in the process of trying to prototype an implementation of reading-order-items, and this case came up. For example:

<div style="display:flex; reading-order-items: flex-visual">
  <div style="order:2">Flex item
    <button>B</button>
    <button>C</button>
  </div>
  <div style="display:contents" tabindex=0> Problem here
    <div style="order:3">Flex item <button>D</button></div>
    <div style="order:1">Flex item <button>A</button></div>
  </div>
</div>

In this example, the sequential focus order should be A, B, C, D. There's no well defined "place" to put the display:contents div, since a) it isn't a flex item that can be ordered according to the flex visual order, and b) it can wrap flex items that aren't even contiguous. There's a similar (and slightly more complicated) case for <slot>s within a flex container like this.

I propose these display:contents elements within a reading-order-items container should simply be declared non-focusable entirely. Unless there's a compelling use case for doing that?

The case for <slot> gets more complicated, since a <slot> forms a focus navigation scope which must be traversed in its entirety before returning to the owning scope. We think we have a solution for that, maybe, but that's likely a good candidate for another issue. But it'd be simplified, here, by saying <slot> (which is display:contents by default) cannot itself be focusable within a reading-order-items container.

@rachelandrew
Copy link
Contributor

I think that makes sense, if you have used display: contents I don't see why you would also want to include it in the order. I'd be interested if anyone can think up an example of needing to do so.

@emilio
Copy link
Collaborator Author

emilio commented May 24, 2024

A fieldset with display: contents and the form controls reordered inside or so, perhaps?

@mfreed7
Copy link

mfreed7 commented May 24, 2024

A fieldset with display: contents and the form controls reordered inside or so, perhaps?

That's a good use case generally, but I don't think (?) you'd want to be able to focus the fieldset itself in that example, would you?

@dizhang168
Copy link
Member

On this topic, here are a few more tricky cases where having display: contents on a flex item causes unclear reading order.

What should be the reading order if reading order items are defined inside a slot (has display: contents) and cross navigation scopes?

<!DOCTYPE html>
<meta charset="utf-8">
<div>
<template shadowrootmode="open" shadowrootdelegatesfocus>
<style>
.wrapper {
display: flex;
reading-order-items: flex-visual;
}
</style>
<div class=wrapper>
<button id="A" style="order: 2">Item A</button>
<slot></slot>
<button id="C" style="order: 4">Item C</button>
</div>
</template>
<button id="B1" style="order: 1">Slotted B1</button>
<button id="B2" style="order: 3">Slotted B2</button>
</div>

Which will render to:
image
Source order: A,B1,B2,C
Visual order: B1,A,B2,C

Given the flattened tabindex-ordered focus navigation scope, step 2.2, we should visit all elements within a scope together (so B1,B2 together). However, that is visually the wrong order.

What should be the reading order if reading order items are defined inside a display: contents shadow root and cross navigation scopes?

<!DOCTYPE html>
<meta charset="utf-8">
<style>
 .wrapper {
   display: flex;
   reading-order-items: flex-visual;
 }
 </style>
<div class=wrapper>
 <div style="display: contents" id="root">
   <template shadowrootmode=open>
     <slot></slot>
   </template>
   <button id="A2" style="order: 2">A</button>
   <button id="B2" style="order: 1">B</button>
 </div>
 <button id="C" style="order: 3">C</button>
</div>

Which will render to
image
Source order: A,B,C
Visual order: B,A,C

Here, we have a DIV that is:

  • Shadow root (so a focus navigation scope owner)
  • Its layout parent is a reading order container
  • Has display: contents

A reading order item is defined using layout information. And in this case, this DIV is invisible to the layout object. Should the DIV qualify as a reading order item? My thinking is yes or else we wouldn't be able to visit its content.

@dizhang168
Copy link
Member

For more context on the points raised above about display: contents and slots, please refer to our HTML standards proposal. It has a suggested algorithm, visual examples and more details in the open questions about this specific problem.
whatwg/html#10407

@dizhang168
Copy link
Member

To summarize, the questions are:

  1. Should a display: contents (with tabindex=0) be considered a reading order item?
  2. Should a display: contents’ children be considered reading order items?
  3. HTML standard expect to traverse within focus scopes, where a focus scope owner can be a shadow host, a slot, a document, etc. This conflicts with reading order, where we are depending on a flattened tree traversal and display: contents/slots don’t matter.

Potential resolutions:

  1. Make display: contents elements not reading order focusable.
  2. Make display: contents children not reading order focusable (fallback to using source order).
  3. Tell users to avoid display: contents for reading order.
  4. Or other suggestions and considerations?

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-display-4] Define how reading-order / reading-order-items interact with focusable display: contents elements., and agreed to the following:

  • RESOLVED: reading-flow does not affect whether an element is focusable
The full IRC log of that discussion <bramus> rachelandrew: issue around how our new reading-flow property interacts with focusable display: contents elements
<bramus> … got input from mason and di in the issue
<bramus> … question is from di at the bottom
<bramus> … should a display: contents with ?? be considered reading order items?
<bramus> … di also suggested that display: contents elements really arent focusable
<bramus> … can make it so that display: contents children are not reading order focusable
<bramus> … would love to hear thoughts
<bramus> dbaron: there are a bunch of complicated issues here
<bramus> … because on the one hand weve gotten feedback from a11y folks tha focusability and ?? should match each other
<bramus> … you shouldnt be able to do sth that takes an item out of fcous order but not the a11y tree
<bramus> … things like that
<astearns> s/??/reading order/
<bramus> … when you are saying that reading order should depend on box order it doesnt make sense to go through a thing that doenst generate boxes
<iank_> q+
<bramus> … easy way out is to say that if you are using one of the readingflow values that depend on box order that elements with display: contents are not part of that order, ie not focusable
<bramus> … not ideal from a11y POV i think
<bramus> … I have an almost finished project to make elements with display: contents focusable but hasnt happened yet
<bramus> … pulling that back would be a partial reverse of the change to make display: contents focusable
<bramus> … alt is to come up with some rule that says where it goes in the order
<bramus> … not hard to make that rule, might be hard to impl
<bramus> … doing the right thing for a11y vs doing a thing that is implementable/describable
<bramus> astearns: is your change that the element with display: contents is focusable or that its children are focusable?
<bramus> dbaron: the element
<astearns> ack iank_
<iank_> ```
<iank_> <div style="display: contents;">
<iank_> <div>1</div>
<iank_> <div style="order: 5;">2</div>
<iank_> </div>
<iank_> <div>3</div>
<iank_> ```
<bramus> iank_: there’s a case that i pasted here in irc
<bramus> … with the order prop and grid/flex reordering things you can pull items bc display: contents doestn have a box you can pull out of the display: contents and the iteration order doesnt become clear
<bramus> … in this case here, the order would be 1 3 2
<bramus> but display: contents is wrapping 1 and 2
<bramus> … so maybe we shouldnt consider display: contents
<bramus> … there might be other solutions
<astearns> ack fantasai
<bramus> fantasai: def an awkward situation. if author asks for it to be focusable then we should try to
<bramus> … would mean to figure out a place to put it in the order
<bramus> … before any other items it contains would make sense
<bramus> … even if they are split across multiple places
<florian> q+
<bramus> dbaron: to poke some holes into that
<bramus> … 2 edge cases
<bramus> … 1 of them is the item has no children at all and therefore ther eis no box at all
<bramus> … other thing is that child is also display: contents
<bramus> … no children at all is messy
<bramus> … other thing leads to recursion
<bramus> fantasai: no contents: if we were reordering all the items and ?? between prev and next siblings
<bramus> … if we reorder those then we could give up and shove it up the end
<bramus> … not sure what authors would expect
<bramus> … between the two makes sens
<astearns> ack florian
<bramus> … we might fix either attach to the prev or attach to the next as a sort of option so that at least when they are together it lands in the middle
<bkardell_> s/sens/sense
<bramus> florian: can i suggest to go the opposite route and say that display: contents does not apply to focusable elements?
<bramus> fantasai: interesting
<bramus> TabAtkins: that would break specs though … the TOC in it for example
<bramus> florian: but does it need to be focusable?
<bramus> TabAtkins: you can tab into the children spans
<bramus> fantasai: ????
<bramus> TabAtkins: if you prevent focusable elements from becoming display: contents then it would break ?????
<bramus> florian: but the a is
<bramus> TabAtkins: this is a focusable <a>
<bkardell_> q+
<bramus> … the fact that its used in a TOC for spec suggests that ???
<bramus> kbabbitt: is it actually focusable?
<astearns> s/kbabbitt/bkardell_/
<bramus> TabAtkins: it does not. what lforian said is to prevent focusable elements from becoming display: contents
<bramus> bkardell_: a is focusable if it has an href
<bramus> TabAtkins: it does, wouldnt use a otherwise
<bramus> florian: you mean that every entry in it is an a?
<bramus> TabAtkins: yes, but i am positioning in the grid the contents of it
<astearns> ack bkardell_
<bramus> florian: to keep pushing … tab’s case is an important point but its a subset
<bramus> … if we had ::contents the bit that needs to be focusable is that
<bramus> … you dont have element with a bunch of children that might or not be focusable
<bramus> … you want to layout the ::before and ::after
<bramus> … the part that is focusable is everything except those
<bramus> … seems a subcase of I have a focusable element with stuff underneath
<bramus> … seems that this case is less ? than the whole problem space
<bramus> TabAtkins: was using this as an example to counter your request
<bramus> florian: yes, but I think its a subcase
<emilio> I think this is a huge tangent, I don't think we should make display: contents not work like that
<bramus> TabAtkins: correct solution here is to use subgrid here. there are other solutions here
<emilio> We either do what we do now (display: contents makes stuff not focusable), or make display: contents focusable and deal with it
<bramus> astearns: given that we cant change other behaviors, what should we do here?
<bramus> florian: for this case: kind of has an obv answer.
<astearns> s/that/the likelihood that/
<bramus> … it is effectively everything except before and after that remains focusable
<bkardell_> q+ for miriam
<bkardell_> q+ miriam
<bkardell_> q-
<emilio> q+
<bramus> … which I think is different from situation where you have a bunch of child elements and then you cant place those
<bramus> rachelandrew: I feel like if in the situation where the author has asked to make it focusable then we have to honor that
<bramus> … the default propably is that its not focusable
<bramus> … its a visual hting we are doing with reading-flow
<bramus> … general use case gonna be that ???
<bramus> … if people asked to make the box focusable then we need to consider some of elika’s suggestions
<bramus> florian: or go back to my other suggestion. if you set tabindex on display: contents then you cant
<lwarlow> q+
<bramus> s/if you set tabindex on display: contents then you cant/if you set tabindex on then display: contents does not apply
<florian> q+
<astearns> ack miriam
<bramus> miriam: currently a11y experts have said us not to use display: contents bc browser bugs and regressions
<bramus> … not reliable to use display: contents on anything that needs semantics
<astearns> ack emilio
<bramus> … sara soueidan recently mentioned it again at css day
<bramus> emilio: we should stop discussion making display: contents not work on focusable things
<bramus> … i think it would be super confusing to do
<bramus> … can decied that display: contents elems are not focusable
<bramus> … not a big deal i think, but opinions
<astearns> q+
<bramus> … or can deal with reading order ??
<florian> q-
<bramus> … cant overfocus on one case specifically (e.g. tabs example)
<astearns> ack dbaron
<bramus> dbaron: rachel suggested to (IUC) sort of make setting tabindex be a stronger indication of focusability that would override some other things that make it non focusable
<bramus> … this scares me bc the rules are already very complicated
<bramus> … an overriding layer seems like a huge mess
<astearns> ack lwarlow
<bramus> lwarlow: i dont fully understand the problem
<bramus> … display: contents is used a lot with shadow dom
<bramus> … largely due to other issues with shadow root
<bramus> … suggestion of making the children of display: contents dont work with reading order feels strange
<bramus> … my intuition would be to ignore display: contents and treat it as if those children were where that display: contents element is
<bramus> … ??? even if source order doesnt match that
<bramus> … so making display: contents focusable here seems like wrong thing
<bramus> emilio: I thought idea was to make display: contents element not focusable / reachable by tab
<bramus> … but maybe I misunderstood
<bramus> dbaron: thats what i was thinking at least
<bramus> … agreeing with emilio here
<florian> q?
<bramus> emilio: so basically it would work but we wouldnt be able to ??? an element that would be ??? if you are reading visual order
<emilio> s/???/reach by tab/
<bramus> rachelandrew: i think that was the orig thinking. to not focus an element if you were doing that
<emilio> s/???/display: contents/
<florian> q?
<florian> q+
<bramus> … its whether that causes a problem here if we have unfocusable display: contents elems
<bramus> astearns: i think im confused
<bramus> … suggestion to do a copout but to have a principle that what we do with reading=flow and display: contents should be same as what we do with focusabilyt and display: contents
<astearns> ack astearns
<bramus> … not sure if that is actually desirable given the last few comments
<astearns> ack fantasai
<florian> q-
<bramus> fantasai: would be unexpected if lets say you have flexbox and use display: contents on some child and on some other item you set order: -1 and then you set reading-flow
<bramus> … even if you didnt do any reordering, the display: contents elem in the middle would disappear from the tab order
<bramus> … would be unexpected
<bramus> … and probably not notice dby many, so probably shouldnt do
<emilio> q+
<florian> q+
<bramus> … elems should remain focusable
<bramus> … best to put it before the first item that uses it
<bramus> … best place if it had no children attach to element before or after or both if ????
<bramus> … if youve to a working layout without reading order then it shouldnt break
<astearns> ack emilio
<bramus> emilio: slight counterpiont: if you make display: contents elem focusable. any visual feedback … you would already need to be careful with its styles, e.g. a link with an outline … youd have to style descendant or something
<bramus> … less concerned about authors accidentally removing it from tab order
<lwarlow> q+
<bramus> … its unfortunate but its a can of worms
<miriam> browser issues documented: https://adrianroselli.com/2022/07/its-mid-2022-and-browsers-mostly-safari-still-break-accessibility-via-display-properties.html
<bramus> … personal preference to make display: contents not focusable
<bramus> … but i get it
<astearns> ack florian
<miriam> and current state noted on caniuse: https://caniuse.com/css-display-contents
<bramus> florian: maybe thats just me, but i think we are talking in the abstract and maybe therefore cant find the right thing to do. need usecases and think on the basis of what people are actually doing with display: contents
<miriam> seems buttons are the primary remaining issue in most browsers
<bramus> … we are going in circles i thikn
<bramus> fantasai: if its focusabl ein the middle of the list wihtout reading order items and then applying it makes it no longer focusable … seems wrong
<bramus> florian: i agree in principle but we should know what people are doing with it
<bramus> … we know of tabs cases here but what everyone is doing here
<bramus> fantasai: ???
<emilio> q++
<emilio> q- +
<emilio> q+
<bramus> florian: agree. just confused by combinatin of statement by a11y people saying dont do it and us doing ???
<bramus> fantasai: (missed)
<fantasai> s/???/if I have a flexbox and it contains an item with 'display: contents' that's focusable and it is reachable now, and all I do is flip reading-flow on the flexbox, that *should not change the focusability of its children*/
<bramus> astearns: this is getting heated … emilio wanted to reply?
<astearns> ack emilio
<bramus> emilio: swithcing reading order wihtout display: contents can change to top order with shadow dom in various ways
<astearns> s/heated/more heated than it needs to be/
<bramus> … maybe that expectation is already broken? bc of how shadow dom tab scoping order works
<bramus> fantasai: there is a difference in changing the order making it not tabbable
<bramus> emilio: thats fair
<bramus> lwarlow: 100% agree with elika
<bramus> … cant change unrelated element and then suddenly make it no longer focusable
<florian> s/us doing ???/us figuring out what happens if you do it, without considering why people are doing it
<bramus> … changing tab order is what you expect
<bramus> … not focusable is not
<emilio> q-
<bramus> … not durable
<astearns> ackl lwarlow
<emilio> ack lwarlow
<bramus> … important to understand use cases, but tangent to this problem
<astearns> s/durable/doable/
<bramus> … you may not even know if you have a display: contents child
<bramus> … it should still be focusable
<bramus> … if you are using a web component from somewhere else, you have no control over it
<bramus> … i dont think we can make it suddenly not work
<bramus> … also "don’t use display: contents"
<TabAtkins> in retrospect it's kinda a fundamentally bad idea, tbf
<bramus> … reason for that is that its historically broken in browsers, not that its a bad idea
<florian> q+
<chrishtr> q+
<bramus> … cant disregard whole usecase because historical issues
<miriam> [nods]
<bramus> astearns: can maybe resolve on that reading flow should have no effect on focusability
<astearns> ack dbaron
<florian> q- later
<bramus> dbaron: regarding fantasai’s example: example 1st and 2nd time was slightly different
<bramus> …the 1st time it was setting order, 2nd time reading-flow
<fantasai> 1st example: flexbox containing e.g. 5 items, with 3rd item `display: contents` element, and last item with `order: -1`
<bramus> … what i was suggesting for if we need a condition for when these things might not be focusable, it would be only for use of reading-flow not order, rather than both
<fantasai> 2nd example: flexbox containing an item with `display: contents` and no use of reordering
<bramus> … there is a distinction between both
<florian> qq+
<bramus> … other thing: what luke already said: i think what we are trying to do here is fix the reasons why a11y folks are saying not to use this stuff
<florian> q-
<bramus> … bc people have use cases. only thing is that a11y folks say its currently broken
<bramus> chrishtr: concrete example from mason (2nd comment int he issue) display: contents elme with tabindex with 2 children
<bramus> … difficulty stems from conflict of values of order and tabindex of parent
<bramus> … not sure why this problem is specific to display: contents
<bramus> … wouldnt a parent with tabindex and order children cause problems even if parent was not display: contents
<bramus> lwarlow: order property woulnd taffect thme
<bramus> chrishtr: only ????
<bramus> lwarlow: thats my understanding
<bramus> dbaron: issue with masons thing is that ?? is reordering its grandchildren because it has display: contents
<bramus> chrishtr: could we resolve by causing display: contents to act like some kind of order affecting stacking content group (?)
<kizu> q+
<bramus> … could have a display: contents cause a flex item children to all have continous ordering
<astearns> ack chrishtr
<bramus> dbaron: thats probably not a compat problem I guess
<bramus> iank_: doesnt work for grid bc you can place grid items in any row/col
<dbaron> s/not a/a/
<bramus> chrishtr: do you have an exmaple?
<bramus> TabAtkins: notion of keeping them together as a group. in grid each item is individually placed
<bramus> chrishtr: but you can specify order on grid children, right?
<florian> q+
<bkardell_> s/exmaple/example
<bramus> … suggestion to reinterpret order for children of display: contents elements
<bramus> TabAtkins: nesting their order?
<bramus> chrishtr: yes
<bramus> iank_: would be surprising to authors
<bramus> … bc it wouldnt read in that order anymore
<bramus> astearns: i think we are going to have to wrap up
<astearns> ack florian
<bramus> florian: unless i misunderstood, chris has an interesting thing to focusalbe children of a display: contents elem
<bramus> … IUC thats not what your proposal adddresses
<bramus> … can be intersting, but doesnt solve this problem
<bramus> chrishtr: maybe I misunderstood mason’s example
<bramus> dbaron: I think its not that you have to go in and out, but its not clear where to put the parent in the tab order
<bramus> kizu: from a11y POV this case is violation. you cant have interactive elements nested inside other interactive ones
<bramus> … for when display: contents we should use focsable
<bramus> … maybe we can split focusable area into multiple ones?
<bramus> … if we have button with some interactiveelement inside, we split all the text parts around it into two ??? and then split
<florian> +1 to kizu
<bramus> … this way whatever we do, order would be logical from author POV
<bramus> … focus button, then text, then ???, then 2nd textnode
<astearns> ack kizu
<bramus> … when we consider all consecutive non interactive parts of display: contents as separate focusable areas we can mix with other interactive elements inside
<bramus> … with this solution wec an solve reading order and bigger issue with nested elements
<astearns> ack dbaron
<bramus> dbaron: my concern with that is that focus state is something that is in the DOM
<bramus> … given that focus is a thing associated with an element, its not clear how you make clear that an item appears 2 times int he tabbing order
<bramus> kizu: i think it would work, same as when you click
<bramus> … ???
<florian> q+
<astearns> zakim, close queue
<Zakim> ok, astearns, the speaker queue is closed
<bramus> … authors dont want to know which part you clicked, only that you clicked the element
<bramus> … order of things … focus on the text, then inner, then parent again
<bramus> … could be confusing for authors but preserves a11y
<dbaron> (I disagree, but I should probably let other people talk.)
<astearns> ack chrishtr
<kizu> I will comment in the issue
<bramus> chrishtr: 2 points: would be super helpful if you could write that down explicitly
<bramus> … and then walking through that in detail would be helpful when we come back to this issues
<bramus> … if this is an anti-pattern then we need a good thing for readers to get to the content eventually
<astearns> ack florian
<bramus> … would love to learn more too about why this is an anti-pattern
<bramus> florian: I like kizu’s suggestion
<bramus> … html spec distinguishes focusable element vs focusable area
<bkardell_> q+
<bramus> … the area can be an elemenent or part of an element
<bramus> … so there is already a notion of this in the HTML spec
<bramus> … should explore kizu’s idea
<bramus> bkardell_: want to warn about confalting interactive element with tabindex
<bramus> … should be careful about that
<bramus> astearns: so we should take it back to the issue?
<bramus> rachelandrew: so we all believe that ?? should be focusable?
<bramus> florian: maybe can resolve on regardless of what and how that reading-flow doesnt change that
<bramus> fantasai: thats what rachel is syaing
<fantasai> s/??/items with `display: contents`
<bkardell_> s/… should be careful about that/They aren't really interchangeable. There are complex interactive elements that do nest tab indexes and that's expected.
<bramus> florian: i think we are saying the same thing, but wanted to express that in a way we dont block romans thing
<bramus> bkardell_: can agree … and can also agree to make display: contents eventually focusable
<bramus> astearns: but thats a separate issue
<bramus> … shadow dom and at least a bunch of other things
<emilio> reading flow should not make elements not reachable in the tab order or something?
<bramus> … eg fragmentation, formatting context, …
<bramus> … would like to scope this to only effect of reading-flow
<bramus> chrishtr: did we prev resolve to make display: contents focusable?
<fantasai> PROPOSED: reading-flow does not affect whether an element with `display: contents` is focusable
<bramus> dbaron: dont remember off the top of my head
<lwarlow> +1
<bramus> astearns: we have proposed resolution
<dbaron> dbaron: ... which discussions were in CSS and which were in WHATWG
<bramus> … maybe that is too specific?
<bramus> … maybe “reading-flow does not affect whether an element is focusable”
<fantasai> PROPOSED: reading-flow does not affect whether an element is focusable
<bramus> florian: both work for me
<lwarlow> +1
<fantasai> +1
<bramus> astearns: objections?
<bramus> RESOLVED: reading-flow does not affect whether an element is focusable
<bramus> astearns: please keep commenting on the issue and put real world examples
<bramus> … will come back to this later
<fantasai> scribenick: fantasai

@dbaron
Copy link
Member

dbaron commented Jun 13, 2024

To be clear, we didn't finish the discussion here, the resolution above is a partial conclusion that reduces the space of conclusions we could reach here.

@rachelandrew rachelandrew changed the title [css-display-4] Define how reading-order / reading-order-items interact with focusable display: contents elements. [css-display-4] Define how reading-flow interacts with focusable display: contents elements. Jun 13, 2024
@kizu
Copy link
Member

kizu commented Jun 13, 2024

In the meeting I said that I will comment in this issue expanding a bit more on my proposal and the nested interactive elements issues.

  1. If an element has display: contents, but is not focusable, then there are no issues, and its content should participate in the flow as usual, being affected by reading-flow etc.

  2. Otherwise, if an element has both display: contents and is focusable, but does not have any other focusable elements inside, this element's content becomes one focusable area. Example: https://codepen.io/kizu/pen/rNgYzVW — currently, only Chrome allows us to focus this link, Firefox and Safari both ignore it, which is bad.

  3. If an element that has both display: contents and is focusable has one or more other focusable elements inside, my proposal is to split the non-focusable areas (excluding whitespace text nodes) inside that element, making them distinct parts that participate in the tab order in the same way they participate in the reading-flow.

    By “Areas” I mean consecutive elements and text nodes. If there are no valid areas other than the nested focusable element, we first see if there is one with the whitespace and use it, otherwise we need to create an empty area at the beginning of that element and treat it as an absolutely positioned element in a static flow.

    Example of the current state for this: https://codepen.io/kizu/pen/gOJXxgy — inner element can be focused by all browsers, but the parent with display: contents is only accessible as a single area in Chrome, while Safari and Firefox ignore it.

The third case is the most complicated, but it is also a case which is already considered a bad practice: ideally, authors must not nest interactive/focusable elements inside each other. Some references for this:

Articles by @aardrian related to this:

A nested-interactive rule in axe related to this:

While this is a bad practice, we need to guarantee that the users would still be able to access the content in at least some
way.

@chrishtr
Copy link
Contributor

Thanks for the summary! I have a couple of questions.

  • Otherwise, if an element has both display: contents and is focusable, but does not have any other focusable elements inside, this element's content becomes one focusable area. Example: https://codepen.io/kizu/pen/rNgYzVW — currently, only Chrome allows us to focus this link, Firefox and Safari both ignore it, which is bad.

Note: this is only with the --experimental-web-platform-features flag turned on, which enables the DisplayContentsFocusable feature @dbaron is working on.

  • If an element that has both display: contents and is focusable has one or more other focusable elements inside, my proposal is to split the non-focusable areas (excluding whitespace text nodes) inside that element, making them distinct parts that participate in the tab order in the same way they participate in the reading-flow.

By "split" do you mean to find each consecutive subsequence of children and text nodes that are not focusable, and treat them as one focusable group? e.g. for the case of <div style="display:contents"><div>One</div><div tabindex=0>Two</div>Three</div> it'd have three items that participate in the tab order, which would be visually indicated by the bounding rectangle of "One", "Two", and "Three"?

Also, how should we determine the order of them? should all of these dynamically split items be focus-ordered as if they had the same tabindex as the display:contents parent?

By “Areas” I mean consecutive elements and text nodes. If there are no valid areas other than the nested focusable element, we first see if there is one with the whitespace and use it, otherwise we need to create an empty area at the beginning of that element and treat it as an absolutely positioned element in a static flow.

What do you mean by "with the whitespace"?

Also, why "treat it as an absolutely positioned element"?

Example of the current state for this: https://codepen.io/kizu/pen/gOJXxgy — inner element can be focused by all browsers, but the parent with display: contents is only accessible as a single area in Chrome, while Safari and Firefox ignore it.

(note: also only with the Chromium flag I mentioned above)

@kizu
Copy link
Member

kizu commented Jun 13, 2024

Thanks for the notes! Indeed, I tested in the Canary with the flag turned on.

By "split" do you mean to find each consecutive subsequence of children and text nodes that are not focusable, and treat them as one focusable group? e.g. for the case of <div style="display:contents"><div>One</div><div tabindex=0>Two</div>Three</div> it'd have three items that participate in the tab order, which would be visually indicated by the bounding rectangle of "One", "Two", and "Three"?

Yes, this is correct. It is questionable how those should be exposed to the accessibility tree (I don't know what is the best answer: should we announce those with all the element's content? Only the “area”? Something else?), but from a user's perspective those could look like separate entities, and a user can expect to tab through them separately (but that's subjective, and different users could expect different things; but I don't think we need to have a control over this, given we are covering a misuse case).

Also, how should we determine the order of them? should all of these dynamically split items be focus-ordered as if they had the same tabindex as the display:contents parent?

Yes, if there is a tabindex present on an element with display: contents, all its “areas” should inherit it, but the other focusable elements inside should not (as it works now with the regular nested interactive elements: the parent with tabindex is separate, the children are kept in the normal tabindex order). If there is not tabindex, then the tabbing order should follow the reading order (so, could also be controlled by reading-flow).

What do you mean by "with the whitespace"?

<a>
    <span tabindex="0"></span>
</a>

In the above code, there are two text nodes containing only whitespace: between <a> and <span and between </span> and </a>. I imagine that for a browser it would be easier to use one of those nodes as the focusable area.

Also, why "treat it as an absolutely positioned element"?

This is only for a case like <a><span tabindex="0"></span></a> — there are no text nodes between the tags, but, ideally, we'd need to have something that could represent the focus state, ideally with a focus ring over it. As it is not a real element, we need to somehow position it, and given the flow can be anything, the least intrusive way to treat it could be to use the same “placeholder” absolutely positioned elements have in their “static” position. But maybe there are other, better, ways to handle this.

@dizhang168
Copy link
Member

Hi @kizu! So, if I understand correctly, you are saying the behavior with feature DisplayContentsFocusable on in Chrome is what you expect.

If we look at the problem Mason shared:

<div style="display:flex; reading-order-items: flex-visual">
  <div style="display:contents" tabindex=0> Problem here
    <div style="order:3">Flex item <button>D</button></div>
    <div style="order:1">Flex item <button>A</button></div>
  </div>
</div>

Are you saying the order should be display: contents -> A -> D?
Or should we be splitting it further into smaller focusable areas?

Yes, if there is a tabindex present on an element with display: contents, all its “areas” should inherit it, but the other focusable elements inside should not (as it works now with the regular nested interactive elements: the parent with tabindex is separate, the children are kept in the normal tabindex order). If there is not tabindex, then the tabbing order should follow the reading order (so, could also be controlled by reading-flow).

Could you give an example for this? Given a display contents DIV, you propose splitting it into multiple focusable areas and let them all have the same tabindex. Does it mean this DIV will get focused multiple times instead of just once during keyboard navigation? I feel like that might not be intuitive to the web users.

Also, would love your input on how this proposal would work with the changes I am proposing at whatwg/html#10407. Thanks!

Side note, I have written and landed some tentative WPT tests for reading-flow here. Maybe this can help visualize different cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Thursday morning
Development

No branches or pull requests

9 participants