Search code examples
htmlhtml-tableaccessibilitywai-aria

Making a vertical table accessible


I have some very basic data, like this:

{
  "name": "John Doe",
  "city": "Minneapolis",
  "state": "Minnesota",
  "country": "United States",
  "age": "42"
}

I need to display it like this:

| name    | John Doe      |
| city    | Minneapolis   |
| state   | Minnesota     |
| country | United States |
| age     | 42            |

As you can see the table above has the headers left justified and the row values are all aligned.

According to W3, the way to do a vertical table is like the snippet below, but they also call out:

Note: Some screen readers will read “Date – Event – Venue” in the “Venue” cell because the direction of the <th> elements is ambiguous.

table th {
 text-align: left;
}
<table>
  <tr>
    <th>Name</th>
    <td>John Doe</td>
  </tr>
  <tr>
    <th>City</th>
    <td>Minneapolis</td>
  </tr>
  <tr>
    <th>State</th>
    <td>Minnesota</td>
  </tr>
  <tr>
    <th>Country</th>
    <td>United States</td>
  </tr>
  <tr>
    <th>Age</th>
    <td>42</td>
  </tr>
</table>

My question is how accessible is a vertical table like this, and would I be better off using a <ul> with some flexbox or grid magic to get my styling requirements and setting the data as a list? Is there an alternative I'm not considering?


Solution

  • Tables are absolutely accessible to screen readers when coded properly. The only thing missing in your example (and the W3 example) is the scope of the <th>. You should always specify the scope attribute so that it specifically says if the table header is for a row or a column. Don't rely on the browser or the screen reader to "guess" at the meaning when you leave scope out.

    There is nothing ambiguous about the direction of the header when scope is specified.

    <table>
      <tr>
        <th scope="row">Name</th>
        <td>John Doe</td>
      </tr>
      <tr>
        <th scope="row">City</th>
        <td>Minneapolis</td>
      </tr>
      <tr>
        <th scope="row">State</th>
        <td>Minnesota</td>
      </tr>
      <tr>
        <th scope="row">Country</th>
        <td>United States</td>
      </tr>
      <tr>
        <th scope="row">Age</th>
        <td>42</td>
      </tr>
    </table>
    

    Now when a screen reader user navigates to a data cell, for example "Minneapolis", and then they navigate to the next cell down using a table navigation key (such as ctrl+alt+downarrow), they will hear the row label announced first and then the data cell value, such as "State, Minnesota".