Responsive Accessible Data Tables with jQuery

Today’s expert post comes from Dylan Barrell, Deque’s Vice President of Product Development. Dylan has almost 20 years of experience in technology development, technical sales, product management, product marketing, and corporate development. Dylan believes in leading through action to create value for shareholders and the community.

Responsive Accessible Data Tables with a jQuery Plugin

There are a handful of blog postings on accessible tables, the best of which is on Accessible Culture. But they all end up leaving us with a couple of problems:

  • When the tables get rendered in the format for the smartphone-sized device, they no longer appear to the AT as a table and the user then loses important abilities to easily navigate the table from column-to-column and row-to-row
  • The responsive tables can only be laid out in a row format – i.e. it is not possible to create a responsive table laid out in columnar format on a desktop and columnar sequential format on a smartphone sized device

Accessible Culture’s CSS solution goes quite far towards a solution, so I took that and built on it while at the same time solving the two problems mentioned above. The code has been included in the a11yfy jQuery plugin. The plugin uses JavaScript to apply responsiveness to an existing table and creates the CSS automatically if asked. The code can be found at the a11yfy GitHub page. Here is a synopsis of the important bits:

  • When the tables get rendered in the format for the iPhone, they no longer appear to VoiceOver as a table and the user then loses important abilities to easily navigate the table from column-to-column and row-to-row. The important bit here is the row-to-row navigation using the rotor.
  • Because of the fact that responsive CSS basically flows oversized elements to stack them vertically, the elements that appear adjacent must be located next to each other in the table. This means that responsive tables can only be laid out in a row forma – i.e. it is not possible to create a responsive table laied out in columnar format on a desktop and columnar sequential format on a smartphone sized device by purely using CSS.

In order to solve the aforementioned problems, the a11yfy jQuery plugin needs to:

  1. Get the AT to treat a sequentially laid-out table as a table, and
  2. Get columnar tables to switch from columnar format on the desktop to row format on a smartphone at the responsive breakpoint

CSS changes to reflow a table accessibly

It turns out that ATs look at the display property when deciding whether or not to treat a table as a table. This does not make any sense to me, but it is the current situation. So the CSS generated by the a11yfy plugin (based on the Accessible Culture CSS) changes the td and th cells to display:block. Also, in order for the AT to recognize the table as a table, it needs to have both a <thead> element and a <tbody> element. Omitting either of these will cause the AT to not recognize the table correctly. However, when the responsive CSS is applied, the <thead> elements will not be interpreted properly by the AT (at least not consistently). For this reason, the generated CSS also hides any <tr> elements inside the <thead> These two changes allow the table to be flowed responsively and still be recognized by the AT as a table – maintaining the header announcement and table navigation in both layouts.

Generated CSS for a breakpoint of 980px width

@media
(max-width: 980px) {
  /* Force table to not be like tables anymore but still be navigable as a table */
  table, thead, tbody, tr {
    width: 100%;
  }
  td, th {
    display: block;
  }

  /* Hide table headers with display: none because accessibility APIs do not pick up reliably on these headers anyway */
  thead tr {
    display:none;
  }
  tr { border: 1px solid #ccc; }
  td, th {
    /* Behave  like a "row" */
    border: none;
    border-bottom: 1px solid #eee;
    position: relative;
  }
  td:before, th:before {
    /* Now like a table header */
    position: absolute;
    /* Top/left values mimic padding */
    top: 6px;
    left: 6px;
    width: 45%;
    padding-right: 10px;
    white-space: nowrap;
  }
}

Switching from columnar to row at the breakpoints

The problem of switching from columnar to row structure at the appropriate breakpoint is solved by a11yfy with JavaScript that:

  1. Detects the size of the window when the table is “a11yfied” and draws the appropriate table structure, and
  2. Attaches to the resize events of the window and then redraws the table appropriately depending on the new window dimensions

Here is a snippet of code showing the important bits of this. You will also notice that a11yfy sets a timeout that is cancelled on subsequent resize event so that the table is not redrawn until the resize events stop being generated for at least 50 milliseconds. This is to avoid constant redraws as the user drags the window to resize it.

dimensions = getDimensions();
drawTable( $table, data, headers, dimensions, opts);
jQuery(window).on("resize", function () {
    newDimensions = getDimensions();
    if (!equalDimensions(newDimensions, dimensions)) {
        if (resizeTimer) {
            clearTimeout(resizeTimer);
            resizeTimer = undefined;
        }
        dimensions = newDimensions;
        resizeTimer = setTimeout(function () {
            drawTable( $table, data, headers, newDimensions, opts);
        }, 50);
    }
});

Using a11yfy against an existing table is quite simple and well documented. Here is some code that shows its use with a small sample table.

<!DOCTYPE html>
<html>

<head>
<script src="../tests/jquery.min.js"></script>
<script src="../a11yfy/jquery.a11yfy.core.js"></script>
<script src="jquery.a11yfy.tables.js"></script>
<script src="../i18n/jquery.a11yfy.i18n-de.js"></script>
</head>

<body>
<table id="responsive">
    <thead>
        <tr>
            <th scope="col">Nelson Mandela</th>
            <th scope="col">Steve Nash</th>
            <th scope="col">Sasha Pieterse</th>
            <th scope="col">J.R.R. Tolkien</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
        </tr>
        <tr>
            <td>95</td>
            <td>39</td>
            <td>17</td>
            <td>81</td>
        </tr>
        <tr>
            <td>Former political prisoner who upon his release was elected president of South Africa in 1994.</td>
            <td>NBA legend who won the MVP in 2005 and 2006 with the Phoenix Suns, and played in eight NBA All-Star games.</td>
            <td>Teen actress who played Alison DiLaurentis on the hit ABC Family series Pretty Little Liars.</td>
            <td>English author, poet, and professor who created The Hobbit and The Lord of the Rings trilogy.</td>
        </tr>
    </tbody>
</table>

<script>
jQuery(document).ready(function (e) {
    jQuery('#responsive').tables({
        sortFilter: 'none',
        responsive: {
            breakPoint: 980,
            css: true
        }
    });
});
</script>

</body>
</html>

There is a bit more to the a11yfy plugin; for example it also implements a sortable/filterable table that does not pollute the header announcements, has functions for portable aria-live announcements and for managing focus in a reliable way when VoiceOver is turned on on an iOS device, has an ARIA menu implementation and more.

This blog posting is based on two postings I did on my personal blog: responsive accessible data tables and jQuery a11yfy plugin implements accessible responsive data tables

You may still want to read the Accessible Culture posting because that solution utilizes :before content to add visible headers to every cell and you might be interested in that technique. If you do modify the a11yfy jQuery plugin to support :before content, be sure to submit a pull request so I can integrate your changes. Alternatively, if you have suggestions for how it could be modified but not the time/skill to do it, connect to me on GitHub, @unobfuscator or @dylanbarrell.

To learn more about accessible coding with jQuery, register now for the jQuery Accessibility Summit.

 

photo of Dylan Barrell

About Dylan Barrell

Dylan is Deque's CTO and leads product development initiatives. He works to help to build a barrier-free web by making it really easy for developers, quality assurance engineers and content writers to create accessible applications and content. Dylan has an MBA from the University of Michigan and a BS from the University of the Witwatersrand.