aria icon indicating copy to clipboard operation
aria copied to clipboard

Should the 'row' role really be necessary for parents of 'gridcell' and other cell role elements?

Open turjmner8 opened this issue 11 months ago • 18 comments

Discussed in https://github.com/w3c/aria/discussions/2128

Originally posted by turjmner8 February 22, 2024 In general, would it be possible to remove the requirement for role 'gridcell' elements to be contained within role 'row' elements in a future spec? Newer DOM approaches like CSS grid are available to simplify the construction of grid structures that do not really support having a row-like element wrap all the given 'cell' elements of a logical row. Additionally, it's not quite clear to me how someone would be able to construct a 'row' role compliant grid for cases where cells span multiple rows without using TR elements, which introduces other sizing issues that do not exist when using more modern DIV / CSS strategies.

It seems like aria-rowindex, aria-colindex, etc... on 'gridcell' role elements themselves should be enough to convey what logical row and column a given 'gridcell' element belongs to even if its parent was a 'grid' role element rather than an additional 'row' role element.

I may be missing some nuance here, but the only thing that seems a little unclear would be not being able to set aria-selected on the containing 'row' element if row selection is supported. In general, it also feels like selections when dealing with tables/grids could also benefit from some enhancements though (how to tell if a row vs column vs individual cell is selected for example). Specifying aria-selected on 'row' role elements vs 'gridcell' role elements does not seem to make much of a difference in current screen reader impls (NVDA, JAWS, voiceover, etc...)

Thanks for any feedback / info here.

turjmner8 avatar Dec 20 '24 00:12 turjmner8

I'm wondering if there could be any additional input on this for future consideration. There was some feedback in the discussion I posted initially, though not much activity after that.

Developing higher complexity grid implementations is very difficult to make accessible with the current DOM restrictions that enforce a containing 'row' element for all cells in a logical row. In addition to the comments above, I have requirements where visible row header cells also need their own horizontally scrollable region, and that is impossible to implement in a 'grid' role due to all cells within a given logical row needing to be children of a single 'row' element.

turjmner8 avatar Dec 20 '24 00:12 turjmner8

re-posting the related issues that this touches on - https://github.com/w3c/aria/issues/1138 and my issue that we closed as duplicate https://github.com/w3c/aria/issues/1853

another related issue to consider with this https://github.com/w3c/aria/issues/1386

and this PR might actually counter balance the mentioned gap of not being able to select a row of cells - if a row were not to exist - https://github.com/w3c/aria/pull/2390

All that said - is setting a row to display: contents also a way to mitigate an issues between needing to use a role=row and wanting more styling flexibility with CSS's grid layout? My understanding is that it could help here... but i also admittedly have avoided using that display value due to previous a11y issues

scottaohara avatar Dec 20 '24 01:12 scottaohara

All that said - is setting a row to display: contents also a way to mitigate an issues between needing to use a role=row and wanting more styling flexibility with CSS's grid layout? My understanding is that it could help here... but i also admittedly have avoided using that display value due to previous a11y issues

Oh, that is an interesting idea - I can certainly try out some proof of concepts in that area and will report back on how it goes.

turjmner8 avatar Dec 20 '24 01:12 turjmner8

Sorry for the accidental close - reopened

turjmner8 avatar Dec 20 '24 01:12 turjmner8

+1 on this

nickygencs17 avatar Jan 16 '25 16:01 nickygencs17

At least for my preliminary testing, using display:contents seems to help quite a bit. I still can't get a scenario to work where something like a set of rowheader columns have there own scrollable region, but I am able to move forward with a single scrollable CSS grid implementation so far.

I think it would be still be helpful to not require 'row' elements if there is additional markup that could be introduced to simplify the DOM structure and enable more complex scrollable regions in its place.

turjmner8 avatar Jan 16 '25 16:01 turjmner8

thanks for checking that out @turjmner8. too bad it didn't solve all the use cases you were looking for. but with that said, would you be at liberty to share some examples / reduced test cases with us for what it is you're trying to create? we talked about this a bit in the ARIA working group today, and there was interest in the idea - but people wanted some use cases to check out so they could understand it better.

scottaohara avatar Jan 16 '25 18:01 scottaohara

Discussed briefly in today's meeting: https://www.w3.org/2025/01/16-aria-minutes.html#58d7

spectranaut avatar Jan 16 '25 19:01 spectranaut

thanks for checking that out @turjmner8. too bad it didn't solve all the use cases you were looking for. but with that said, would you be at liberty to share some examples / reduced test cases with us for what it is you're trying to create? we talked about this a bit in the ARIA working group today, and there was interest in the idea - but people wanted some use cases to check out so they could understand it better.

Sure, would be happy to write up a rough codepen of the type of layout - not sure it will have all of the actual keyboard support it eventually will, but at least the simplest core scrolling regions that I am looking to find support for. Thanks!

turjmner8 avatar Jan 16 '25 20:01 turjmner8

Some rough samples - feel free to let me know if anything looks off with them or there are more questions / concerns.

In the first demo below, the individual cells do not have containing 'row' role elements, but have aria-colindex and aria-rowindex set on them to convey their logical rows and columns. This allows the individual cells to be part of a simple CSS grid layout that can utilize sticky positioning for column and row headers as well, and is an example of what I am hoping can become a valid 'grid' role implementation with the requested change.

https://codepen.io/turjmner8/pen/azojNxV

In order to achieve an acc-compliant grid today, using the display:contents suggestions, this next demo shows the same basic grid with additional 'row' role elements. These extra elements don't really cause much of an issue for this simple case, but do have a negative impact on rendering performance of larger grids by a noticeable amount without really adding any new information or functionality when compared to the first demo.

https://codepen.io/turjmner8/pen/QwLBpOx

Finally, the last demo below shows a more complex grid setup where there are multiple row headers that are rendered within their own horizontally scrollable region separate from the rest of the grid body. This is an additional requirement I am working with that I don't believe is achievable with a valid 'grid' role implementation due to the 'row' role requirement. The row headers themselves need to be children of a different scrollable region than the rest of the logical row's cells, but also need to share 'row' element ancestors. The aria markup I've included follows the same pattern as my first demo, where all of the cells (header and non-header) specify aria-rowindex and aria-colindex, which should be enough to convey the logical grid structure.

https://codepen.io/turjmner8/pen/ogvMZdx

turjmner8 avatar Jan 18 '25 04:01 turjmner8

I checked the first example with Firefox: Firefox only recognises the grid, not the gridcell roles. This means that table navigation is not possible at all with NVDA. Chrome, on the other hand, recognises grid and gridcell, but all gridcells are in one row due to the lack of role=row, so that NVDA outputs 32 columns in one row during table navigation.

JAWS-test avatar Jan 18 '25 20:01 JAWS-test

@JAWS-test the point of the demos weren’t that we thought they would work, but we wanted to see what was trying to be achieved

Thanks @turjmner8. This will give the group something to mull over.

scottaohara avatar Jan 20 '25 06:01 scottaohara

Just as a note, one other thing that the my 3rd demo above brings up is how the real DOM order of elements seems to matter more than the aria-rowindex and aria-colindex values for screen readers. If the 'row' requirement is no longer required, it would not be possible to produce that 3rd demo where the actual cells of the 'grid' are fully ordered from top to bottom, left to right in the DOM due to the different scrolling parents of the row headers compared to the body cells.

Even in an otherwise valid 'grid' role implementation today though, if row 2 appears in the DOM before row 1, row 2 is read before row 1 by JAWS. I'm not sure if that is expected or not tbh.

turjmner8 avatar Jan 23 '25 01:01 turjmner8

@aardrian We think you would find this very interesting. Could you find time to read this proposal?

jnurthen avatar Jan 30 '25 18:01 jnurthen

I do indeed find this very interesting and regret my travel schedule kept me from being able to participate.

I want to address OP's comments first and qualify that these are my thoughts alone and probably wrong in exciting and weird ways...

In general, would it be possible to remove the requirement for role 'gridcell' elements to be contained within role 'row' elements in a future spec?

Doing so would only make sense in contexts where the content is not tabular data (a table).

Newer DOM approaches like CSS grid are available to simplify the construction of grid structures that do not really support having a row-like element wrap all the given 'cell' elements of a logical row.

CSS grid is strictly for visual layout, not to represent tabular data. There is an unfortunate overlap with ARIA grid in name, but their purposes are divergent.

Additionally, it's not quite clear to me how someone would be able to construct a 'row' role compliant grid for cases where cells span multiple rows without using TR elements, which introduces other sizing issues that do not exist when using more modern DIV / CSS strategies.

With aria-rowspan. Analogous to the rowspan attribute in HTML.

It seems like aria-rowindex, aria-colindex, etc... on 'gridcell' role elements themselves should be enough to convey what logical row and column a given 'gridcell' element belongs to even if its parent was a 'grid' role element rather than an additional 'row' role element.

They could be, but those attributes exist primarily to provide context for position when not all rows are in the DOM. Think of a paged table, for example. Otherwise the user agent calculates these values on its own.

Relying solely on these values introduces risk when the actual counts differ from the asserted counts, and even more risk when client-side script is used to dynamically alter these values.

I may be missing some nuance here, but the only thing that seems a little unclear would be not being able to set aria-selected on the containing 'row' element if row selection is supported

Indeed, and that would need to be addressed (such as by leaning solely on rowheader and columnheader to convey selectedness).

In general, it also feels like selections when dealing with tables/grids could also benefit from some enhancements though (how to tell if a row vs column vs individual cell is selected for example).

See my prior sentence.

All of this has to be weighed against @scottohara's comment above and the linked open issues.

Now, looking at the use cases (and thank you for those, by the way)…

[…] This allows the individual cells to be part of a simple CSS grid layout that can utilize sticky positioning for column and row headers as well, and is an example of what I am hoping can become a valid 'grid' role implementation with the requested change.

https://codepen.io/turjmner8/pen/azojNxV

Sticky column and row headers can be done in HTML tables. Is there something unique to CSS grid that makes it necessary to remove the row?

[…] These extra elements don't really cause much of an issue for this simple case, but do have a negative impact on rendering performance of larger grids by a noticeable amount without really adding any new information or functionality when compared to the first demo.

https://codepen.io/turjmner8/pen/QwLBpOx

I feel like a perf issue isn't necessarily a reason to remove a requirement (given the knock-on effects referenced in linked issues).

Finally, the last demo below shows a more complex grid setup where there are multiple row headers that are rendered within their own horizontally scrollable region separate from the rest of the grid body. […]

https://codepen.io/turjmner8/pen/ogvMZdx

That is an interesting use case.

Let me toss a different idea here, starting from my understanding so far…

  • all your examples seem to show tabular data;
  • it feels like you are using ARIA grid to avoid HTML tables (not a judgment, just an observation) and not for the ARIA grid interaction model;
  • CSS grid is strictly a layout model, though it can be (has been) used to assemble tabular data visual layouts;

I am wary of diverging from HTML if there is already something in HTML that could be used.

HTML already has <colgroup>. While it does not wrap a column of cells (owing to the linear nature of code), browsers already make sufficient programmatic connections to pass style information to those cells.

ARIA has no equivalent (and hasn't really needed one).

Is there existing support, behavior, patterns, etc. with <colgroup> that could be a starting point?

An advantage is, if so, approaches could be percolated back to HTML. Then HTML data tables can become that much more robust and have parity with ARIA grids.

aardrian avatar Mar 26 '25 21:03 aardrian

Thanks for the feedback @aardrian - just some added info:

Most all of my 'grid' role implementations do use HTML 'table' elements today (along with tr's, td's, etc...). I am looking to move away from that in more complex data grid cases due to performance issues and the ease of using more powerful layout tools like CSS grid styling could provide.

For example, having to have a physical 'row' element really does make a large table/grid more sluggish to construct and size during page load. From a data 'grid' perspective, there is not really a difference between requiring a physical row element wrapping all cells in a given row vs requiring a physical column element wrapping all cells in a given column, but you can't require both at the same time and the current 'grid' spec is fine without a 'column' requirement. This makes me think it could also be fine without a 'row' requirement as the presence of that row in a true 2d data structure is arbitrary compared to the lack of requiring a column element.

I can continue to use HTML 'table' elements in some cases, and can even use CSS grid with a 'row' element in other cases despite the performance hit for having the extra row elements, but my last example is the requirement that really makes things challenging. There really is no way to construct a split panes view following the 'grid' role spec today where specific cells in a given row have separate scrollable regions while also being wrapped by a single 'row' element.

https://codepen.io/turjmner8/pen/ogvMZdx

turjmner8 avatar Mar 26 '25 21:03 turjmner8

@turjmner8 not saying it is pretty but it is possible https://codepen.io/jnurthen/pen/azbaNVG

jnurthen avatar Mar 26 '25 21:03 jnurthen

Oh, @jnurthen using aria-owns allows the 'gridcell' elements to not be physically nested within the 'row' elements? That is something I'm not familiar with, but will definitely play around with. If it works properly in JAWs / NVDA (or even should really), that would be great.

turjmner8 avatar Mar 26 '25 21:03 turjmner8

@turjmner8

Most all of my 'grid' role implementations do use HTML 'table' elements today (along with tr's, td's, etc...). I am looking to move away from that in more complex data grid cases due to performance issues and the ease of using more powerful layout tools like CSS grid styling could provide.

I understood that. And the three paragraphs that followed. Your example, which you already linked and to which I responded, is, as I noted, an interesting use case.

To re-ask: Is there existing support, behavior, patterns, etc. with <colgroup> that could be a starting point?

I am asking that not to dismiss your use case, but to better understand what you have already tried. That can save time exploring options that are dead ends. It also allows me to ask other people about their use cases to find where they intersect (though the dual-scrolling use case seems pretty straightforward).

Now, @jnurthen provided a nifty example and you rightly asked if it works in JAWS or NVDA. I am assuming that means you only care about Windows users for your use case. With a very quick test run:

  • JAWS / Chrome allowed table navigation seemed to expose rows and columns correctly.
  • NVDA / Firefox announced cell counts correctly but would not allow table navigation and failed to convey some cell headers.

What this tells me is that either Firefox or NVDA might not parse those aria-owns relationships correctly.

If that aria-owns structure can do what you want visually and user agents / screen readers can expose it correctly, would that satisfy your use case?

aardrian avatar Apr 06 '25 19:04 aardrian

I've been meaning to bring this up for a while too, but haven't gotten around to it until now. The row parental role requirement is problematic for our grids.

Our grids are virtualised, meaning they recycle elements as they are scrolled out of view, filling them with new content and repositioning them as if they are being scrolled into view at the opposite side of the axis. This has important performance considerations with regards to the DOM structure that we cannot really change to accommodate the hierarchy required by accessibility roles. In our data grids, rows can be pivoted to columns and vice versa, so we render each set of row headers, column headers and cells separately to minimise DOM changes which can lead to expensive CSS recalculations.

I would like to ask why the row role is even necessary in the structure of a grid or table. It seems to be important for treegrid, but other than that is it just a relic of HTML tables that got brought over to ARIA? If every cell/rowheader/columnheader in a grid or table is correctly marked up with aria-rowindex and aria-colindex, then the structure can (programmatically speaking) be determined without any contribution from elements with a row role at all. Consider the following small example grid:

Image

This can easily be represented by the following structure:

grid
  gridcell rowindex=0 colindex=0
  colheader rowindex=0 colindex=1
  colheader rowindex=0 colindex=2
  colheader rowindex=0 colindex=3
  rowheader rowindex=1 colindex=0
  rowheader rowindex=2 colindex=0
  rowheader rowindex=3 colindex=0
  gridcell rowindex=1 colindex=1
  gridcell rowindex=1 colindex=2
  gridcell rowindex=1 colindex=3
  gridcell rowindex=2 colindex=1
  gridcell rowindex=2 colindex=2
  gridcell rowindex=2 colindex=3
  gridcell rowindex=3 colindex=1
  gridcell rowindex=3 colindex=2
  gridcell rowindex=3 colindex=3

Being an equal number of rows and columns, pivoting this table whilst adhering to the ARIA required structure would not require any DOM changes at all. However, if there were 4 columns and 3 rows, the ARIA-required structure would need DOM changes to swap columns with rows. It would require the creation of an extra row element and 1 colheader, 3 gridcell would need to change parents, in addition to ARIA attribute and cell content changes. Without row roles, only the ARIA attributes and cell contents need to be updated.

andyearnshaw avatar Jun 20 '25 13:06 andyearnshaw

I strongly agree with reconsidering the requirement for role="row" as a mandatory container for gridcell elements within an ARIA grid.

Modern layout systems like CSS Grid have fundamentally changed how developers structure and render grids. The strict expectation that each set of gridcell elements must be wrapped in a row container is increasingly at odds with how web layouts are built today.

1. DOM Structure ≠ Visual Structure

In a CSS Grid or virtualized rendering model, the DOM no longer mirrors the visual layout. Rows can be dynamic, partial, or virtualized for performance reasons. Forcing an intermediate role="row" element:

  • Adds unnecessary DOM complexity,
  • Creates maintenance overhead for dynamic grids, and
  • Encourages developers to “fake” rows purely to satisfy the spec — which undermines semantics rather than preserving them.

2. ARIA Already Provides Positional Semantics

The ARIA attributes aria-rowindex and aria-colindex (and, where needed, aria-rowspan and aria-colspan) already communicate a cell’s logical position and relationships. When these are present, assistive technologies can infer row structure without requiring a wrapper element.

In practice, screen readers like NVDA, JAWS, and VoiceOver already interpret gridcell position based on these attributes even in the absence of an explicit row role. This suggests that the semantic need for the wrapper has largely been superseded by more granular attributes.

3. Improved Accessibility Alignment

The goal should be to enable authors to express accessible, navigable data relationships without imposing structural requirements that conflict with modern layouts. Removing the strict role="row" requirement would:

  • Make ARIA grids more consistent with CSS Grid and other rendering paradigms,
  • Reduce friction between accessibility semantics and performance-oriented architectures,
  • And allow developers to focus on meaningful relationships rather than markup gymnastics.

4. Backward Compatibility

This change wouldn’t invalidate existing, conformant markup — grids using role="row" would continue to function exactly as before. It simply provides more flexibility for new patterns and frameworks.

ARIA should evolve to describe relationships and meaning, not enforce specific markup shapes that belong to a pre-CSS-Grid era. If aria-rowindex and aria-colindex can already convey these relationships clearly, the row role should be recommended, not required.

nickygencs17 avatar Nov 07 '25 02:11 nickygencs17

This is just a variant of the old idea to have a separate "layoutgrid" role that pays attention to wrapping cell positions in responsive designs which are not possible using a rigid row lattice.

stes-acc avatar Nov 07 '25 07:11 stes-acc

This is just a variant of the old idea to have a separate "layoutgrid" role that pays attention to wrapping cell positions in responsive designs which are not possible using a rigid row lattice.

Except our grids are data grids with cells arranged like traditional tables, not layout grids with wrapping.

I'm not sure another role is necessary either. Ideally, it would involve:

  1. Loosening the strict requirement of role="row" to allow rows to be implicit
  2. Allowing aria-expanded on the role="rowheader" element to maintain support for tree grids

andyearnshaw avatar Nov 07 '25 09:11 andyearnshaw