2

I am creating a React component for tables with expandable rows, and I want to make it as accessible as possible.

Here's a simple, unstyled example of what I'm making:

https://codesandbox.io/s/nz8r2w74j

Whenever I click the "more info" button, a new row is added, with info about the row in front of it.

What do I need to add in terms of wai-aria roles, focus management and other stuff in order to make it truly accessible?

Kris Selbekk
  • 6,246
  • 4
  • 39
  • 68

2 Answers2

2

You essentially have a "disclosure widget". The button that opens/closes the section would have aria-expanded set to true/false.

However, I would not literally add a new row to the table because that might confuse screen readers. When the table is first navigated to, the user will hear the table has four rows (including the header) and four columns. When you click the "more info" button, the table will now have five rows but the screen reader is not going to tell the user that another row appeared. If the user was navigating down the column and hearing the row numbers (which are normally announced by screen readers), they'd end up on row five when earlier they heard there were only four rows in the table.

I don't know if this would work for your case, but in the demo code, the extra info is related to the person so it could just be hidden information (css display:none) that exists in the first table cell. When you select the button, the information is revealed (css display:block).

Also, you would either need to make the name a row header (<th scope="row">) or you'd need to associate the person's name with the "more info" button so that the screen reader knows which person they're getting more info about.

I don't know react but the generated html would either look like this (with row headers):

<tr>
  <th scope="row">Avicii</th>
  <td>Progressive House</td>
  <td></td>
  <td>
    <button>More info</button>
  </td>
</tr>
<tr>
  <th scope="row">Kygo</th>
  <td>Tropical House</td>
  <td></td>
  <td>
    <button>More info</button>
  </td>
</tr>

or would look like this (with additional information associated with the button):

<span id="moreInfoID" class="sr-only">more info about </span>
...
<tr>
  <td id="name1">Avicii</td>
  <td>Progressive House</td>
  <td></td>
  <td>
    <button aria-labelledby="moreInfoID name1">More info</button>
  </td>
</tr>
<tr>
  <td id="name2">Kygo</td>
  <td>Tropical House</td>
  <td></td>
  <td>
    <button aria-labelledby="moreInfoID name2">More info</button>
  </td>
</tr>

The latter is a bit more work. I would recommend the first one.

(You can see info on the sr-only class at What is sr-only in Bootstrap 3?).

Also, your example shows the new row added has tabindex="0". Since the new information is not an interactive object, it should not receive keyboard focus and shouldn't have tabindex.

slugolicious
  • 8,671
  • 1
  • 20
  • 30
  • Thanks! Especially about that row announcement stuff - I didn't know that! Unfortunately, this particular implementation need to be flexible enough for me not to know anything about the content. The expandable content might be related to the first column, or it might not. It also need to span the entire width of the table - which isn't going to work with placing the (potentially very complex) expandable content into the first column – Kris Selbekk Nov 15 '18 at 09:27
  • Yeah, I was kind of afraid of that but wanted to post my initial thoughts and also mention that dynamically adding a row to the table might be confusing for screen reader users. I was still thinking about a more general solution and was going to update my answer if I have time to come up with something. – slugolicious Nov 15 '18 at 15:56
  • Does the "more info" info have to be a row in the table? Can it be displayed as kind of a "mega" tooltip (which would essentially be a modal dialog)? Modal dialogs have their own accessibility challenges, but I can post some resources for that. – slugolicious Nov 15 '18 at 16:04
  • The only time I've seen a table grow dynamically is when rows are added to the bottom of the table, and that's because of a user interaction such as clicking on an "add row" type of button, so it was expected behavior that the table would grow. – slugolicious Nov 15 '18 at 16:19
  • The "more info" info can be whatever, really, but my particular use case is a data heavy workflow where a "pro user" consumes, alters and interacts with a lot of info at once. Triggering a modal could indeed work, but it would also stop the user from being able to look at several detail panels at once, for instance, or comparing one "more info" panel with several other summaries. Perhaps this is best done without a table at all? – Kris Selbekk Nov 16 '18 at 13:20
  • Good points, you can't view multiple modal dialogs at the same time. You *could* view multiple non-modal dialogs, but that seems messy. I didn't realize someone might want to see multiple infos. Tables are good for organizing grids of data and they're very accessible when coded properly (using row and column headers). If your real code is similar to your sample, then a table is the right element. – slugolicious Nov 16 '18 at 15:33
  • I had considered suggesting the info rows be real rows in the table all the time (instead of dynamically added) so the SR user would know the real number of rows, but have the rows visually hidden (like a zero height). The "hidden" rows could be available all the time to SR users and you could associate a hidden column header with them. That's getting into too much detail for this comment section and I'd have to update my answer if you want more info, so to speak. – slugolicious Nov 16 '18 at 15:33
1

You could add aria-expanded="true" to the button when the collapsible section is expanded. And if you have tabindex="0" on the focusabled items in the table (whole table), you wouldn't worry about tab ordering.

I've updated the sandbox: https://codesandbox.io/s/k5pkj4wzw3

For further reading on accessible collapsible sections (read: expandables), I recommend this article: https://inclusive-components.design/collapsible-sections/

phun-ky
  • 220
  • 2
  • 12