htmlaccessibilityscreen-readersjaws-screen-readeraria-role

Are column headers essential in an accessible role="grid" setup?


goal: accessibility

target screen readers: JAWS and NVDA

I am adding role="grid" to a list of items. Each row in the grid contains some grid cells representing the item name, description, etc. I cannot change the markup to use a table so this is why I am using role="grid".

My question first question:

Within the context I am working, it is easier for me to add a visually hidden header to each grid cell rather than adding a separate row to the grid with column headers for each column. Is it ok to label each grid cell with a header rather than creating a row of column headers (role="columnheader")? How will this affect the level of accessibility for screen readers? Do users always expect a grid to have column headers?

My second question:

I want to include some content which is not located within the container I have marked with role="grid" as a grid row. Is it possible to associate content outside the grid container with the grid as a grid row?

NOTE: Keep in mind that altering the markup is not an option so suggestions such as "build it as a table" will not help here.

Thank you!


Solution

  • I cannot change the markup to use a table so this is why I am using role="grid".

    If you can specify role="grid" in your code then it seems like you could specify role="table". Is there a reason that's not possible? The reason I ask is because grids should be reserved for when the actual cell contents can be edited, kind of like a spreadsheet. The fact that a cell has an interactive element in it does not mean it should be a grid. So my first recommendation is to use role="table".

    However, grids are recommended when you have a group of things where you can navigate to each "thing" using the arrow keys.

    I'm guessing you already read the spec for grids.

    it is easier for me to add a visually hidden header to each grid cell rather than adding a separate row to the grid with column headers for each column. Is it ok to label each grid cell with a header rather than creating a row of column headers

    While you could do that, you'll miss out on some of the benefits of real column and row headers. With a basic <table>, it's very helpful for assistive technology users, such as screen readers, to have both <th scope="col"> and <th scope="row">. The latter is often overlooked.

    Picture yourself in the middle of a big table. Lots of rows and columns. You know the current value of the cell in the table because the screen reader just announced it. Now you want to navigate down one cell. If you don't have a row header, then you will not hear any context for the next cell value. If you want to navigate left or right one cell, if you don't have a column header, then you will not hear any context for the next cell value.

    If you hard code the column header as a visually hidden element, then you will always hear that column header announced for the cell even if you are navigating vertically down a column. That would be unexpected behavior for a screen reader user. The column header should only be announced if you navigate horizontally across a row, not vertically down a column. When you navigate vertically, the row headers should be announced.

    I'm not trying to be harsh here but I think you need to go back to your statement:

    it is easier for me

    and decide if the ease of coding is more important than the end user experience.

    If there's a technology reason you can't have column and row headers, because the library you're using doesn't allow it or some other reason, then as a last resort, you can try coding around it with visually hidden element but I would not recommend that as a first choice.

    I want to include some content which is not located within the container I have marked with role="grid" as a grid row.

    That's a little trickier. The aria-owns attribute is exactly what you need but it's typically used when a child element can't be owned by the parent via normal DOM nesting. In your case, it sounds like most of the elements are nested according to the DOM but you'll also have something outside the DOM.

    The tricky part is when you mix the two. As documented in the spec:

    If an element has both aria-owns and DOM children then the order of the child elements with respect to the parent/child relationship is the DOM children first, then the elements referenced in aria-owns.

    So you might get some funky reading order if the literal DOM children are announced first and then the aria-owns children are announced second. Definitely worth a bit of testing. You might have to put an ID on every row, including the content outside the table, then use all of those IDs in aria-owns of the table even those most of the rows are "naturally" owned by the table because of the DOM.