Search code examples
datatableheaderlabelaccessibility

Edge Case Tabular markup for accessibility question


Initial Research:

I have been searching for some time and cannot find any Q&A that answers this specific edge case, only can find info on when to use tables and how tables should be structured so I am hoping someone out there knows.

Background:

I am working with a team to create an accessible website, but we stumbled into a bit of a rabbit hole and are having trouble coming to an agreement.

To our understanding, accessibility identifies tabular data as data that requires a header/label to have any meaning. It also discusses that tabular data should use table markup.

Problem:

The argument comes from what we identified as an edge case.

So on the page, there is a profile of a player's avatar that includes things like player's username, avatar name, avatar level, etc.

This data is laid out on the page with bold text acting as the header/label with the data dynamically populating the section underneath the corresponding header. There is no table markup of any kind here. However, some have tried supplementing label, Aria-label, or other similar means to associate the header/label text to data field, which to my understanding, isn't viable as these are not form fields.

Example:

Username
JosiePosie

Avatar Name
Ragnar

Avatar Level
48

Question:

The argument is that this is identified as tabular data and should be using table markup. Some say that it doesn't need to be in traditional table format on the UI, but just needs the markup, others think it should be in traditional table format with table markup. The rest argue that it's "not a table" so it shouldn't need table markup at all.

It would be greatly appreciated if any fellow accessibility developers and testers could help us understand what the right answer is here. Thank you all in advance.


Solution

  • Accessibility, specifically WCAG 1.3.1 Info and Relationships, essentially says that whatever visual structure is implied through styling must also be conveyed to assistive technology.

    So you are implying a relationship between the bold text and the non-bold text. There is nothing in WCAG that says how you have to convey that relationship. Some options are:

    • table
    • definition list (<dl>)
    • headings

    The easiest is headings.

    <h4>Username</h4>
    JosiePosie
    
    <h4>Avatar Name</h4>
    Ragnar
    
    <h4>Avatar Level</h4>
    48
    

    A definition list also makes semantic sense but unfortunately, different screen readers treat <dl>s differently so you don't get a decent consistent experience for all users, so I would shy away from using one.

    <dl>
      <dt>Username</dt>
      <dd>JosiePosie</dd>
      <dt>Avatar Name</dt>
      <dd>Ragnar</dd>
      <dt>Avatar Level</dt>
      <dd>48</dd>
    </dl>
    

    And as you mentioned, a table is another way. Tables provide a good experience for screen reader users, but so do headings so you don't necessarily have to use a table. If you do go with a table, from a styling perspective, it might be easier to use roles instead of actual <table> elements (although that's based on my lack of CSS expertise to get a table to look like your example).

    You can decide if you want to conceptually have columns of data or rows of data. That is, should Username be a column header or a row header? It doesn't really matter.

    Column headers:

    enter image description here

    Row headers:

    enter image description here

    Remember, this is conceptually. It's how the table would be announced for screen readers. Visually, you can still have your label/value stacked as in your original image.

    As mentioned, not being a CSS guru, I'd find using roles easier than actual <table> markup unless it's easy in CSS to have table "cells" stacked.

    Given your current layout, having row headers is a bit easier. This will visually look like your example and will read as a table with row headers.

    <div role="table">
      <div role="row">
        <div role="rowheader" style="font-weight:bold;">Username</div>
        <div role="cell">JosiePosie</div>
      </div>
      <div role="row">
        <div role="rowheader" style="font-weight:bold;">Avatar Name</div>
        <div role="cell">Ragnar</div>
      </div>
      <div role="row">
        <div role="rowheader" style="font-weight:bold;">Avatar Level</div>
        <div role="cell">48</div>
      </div>
    </div>
    

    (You could use <div>s or <span>s)

    Mimicking column headers is a little more complex because your visual layout implies row headers. So you'd have to use aria-owns to "manually" construct the parent/child relationships.

    The following is close but not quite there:

    <div role="table">
      <div role="row" aria-owns="r1 r3 r5">
        <div id="r1" role="columnheader" style="font-weight:bold;">Username</div>
        <div id="r2" role="cell">JosiePosie</div>
      </div>
      <div role="row" aria-owns="r2 r4 r6">
        <div id="r3" role="columnheader" style="font-weight:bold;">Avatar Name</div>
        <div id="r4" role="cell">Ragnar</div>
      </div>
      <div role="row">
        <div id="r5" role="columnheader" style="font-weight:bold;">Avatar Level</div>
        <div id="r6" role="cell">48</div>
      </div>
    </div>
    

    You end up with 3 rows instead of 2 rows. The last row can't have the role="row" eliminated because that would leave a plain <div> in the table which isn't allowed. But other than that, it reads like a table with 3 column headers. I could work on this code to make it correct but I think the row headers option is better, if you want to use table layout.

    But all this can be avoided if you go with the first option of headings.