How to create a Responsive and Accessible data table
Tags: html, css, javascript
Published: 2020-11-13 18:27:59

---
title: How to create a Responsive and Accessible data table
published: true
description: A responsive and accessible table that works with and without JavaScript
tags: html, css, javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/dxu4c41bb1kwyg45h5al.jpg
---

> <b>The code for this article is based on the work of Adrian Roselli and Chris Coyier in their posts entitled [Responsive Accessible Table](https://adrianroselli.com/2017/11/a-responsive-accessible-table.html) and [Responsive Data Tables](https://css-tricks.com/responsive-data-tables/).</b>

> <b>You can [view the code on GitHub](https://github.com/ziizium/responsive-accessible-table) and [check the demo online](https://responsive-accessible-table.netlify.app/).</b>

## __Introduction__

Tables are used to present data in a tabular format. In this article you will learn how to create a table that's not only accessible but also responsive.

## __Responsive Table__

[Responsive Web Design](https://alistapart.com/article/responsive-web-design/) came around in 2010, but HTML tables did not play nicely with it. In 2011, CSS-Tricks wrote a post about _responsive data tables_ which works without JavaScript and not sacrificing accessibility.

Fast-forward to 2017, Adrian Roselli wrote a detailed post on how to create responsive and accessible table but it uses JavaScript to make it work well on mobile. Without JavaScript, the table occupies half of the screen width on a mobile viewport.

I could not find a way to fix this but I realized that I could combine both techniques into one.

## __Responsive and Accessible Table with or without JavaScript__

The trick is to combine Chris and Adrian's technique. Chris' technique will be the default because it works without JavaScript  and when the browser interprets JavaScript we change to Adrian's technique.

The HTML table has a CSS class `noJS-version`. This class and its related selectors is the CSS code for the responsive table by Chris. You can check the code in [`index.html`](https://github.com/ziizium/responsive-accessible-table/blob/main/index.html) but here is part of it:

```html
<!-- Code truncated to save space -->
<div role="region" aria-labelledby="tableCaption" tabindex="0">
    <table id="worldLeaders" class="noJS-version">
        <!-- Table data -->
    </table>
</div>
```

When JavaScript is available, `noJS-verion` is changed to `js-version` which (and its related properties) contains code for the responsive table by Adrian.

The following JavaScript does the trick:

```js
// Grab the table
let table = document.getElementById("worldLeaders");
// Remove the non JavaScript version by Chris
table.classList.remove("noJS-version");
// Add the JavaScript version by Adrian 
table.classList.add("js-version");
```

Adrian also provides the function [`AddTableARIA`](https://github.com/ziizium/responsive-accessible-table/blob/main/responsivetableroselli.js#L37) which (as it name implies) adds ARIA attribute to the table.

With this you have two versions of the table, available to users with or without JavaScript and also accessible.

## __Screen Reader testing__

There are various screen readers out there, for this article, [NVDA](https://www.nvaccess.org/) was used in testing and the results were welcoming.

### __Screen Reader testing: Without JavaScript__

Without JavaScript, after reading the data before the table (the page metadata and page heading), NVDA recites the table has having __6 rows and 3 columns__ then proceeds to read the table data.

Even on mobile viewport when the first row is not visible it is still available to screen readers because it's only moved off-screen with the following code:

```css
@media only screen and (max-width: 760px),
(min-width: 768px) and (max-width: 1024px)  {
    /* Hide table headers (but not display: none;, for accessibility) */
    tr:first-of-type { 
        position: absolute;
        top: -9999px;
        left: -9999px;
    }
}
```

Here is a partial "transcript" of the page with JavaScript disabled and on a Desktop viewport:

> `Responsive Accessible Table`
`Main Landmark heading level 1 Responsive and Accessible Table that works without JavaScript`
`Region table with 6 rows and 3 columns caption World Leaders and their Currencies`

> `Row1 Column1 Name`

> `Column2 Country`
> `Column3 Currency`

> `Row2 Name Column1 Boris Johnson`

> `Country Column2 Britain`

> `Currency Column3  Pound`

> `Row3 Name Column1 Donald Trump`

> `Country Column2 U.S.A.`

> `Currency Column3 Dollar`

On a mobile viewport, NVDA recites the table differently due to the modifications made to the table for it to occupy the viewport:

> `Row1 Column1 Name`
> `Column2 Country`

> `Column3 Currency`

> `Row2 Column1 Name Boris Johnson`

> `Column2 Country Britain`

> `Column3 Currency Pound`

> `Row3 Column1 Name Donald Trump`

> `Column2 Country U.S.A.`

> `Column3 Currency Dollar`

The main difference is that the screen reader reads the column number before the column data as it's seen on screen.

### __Screen Reader testing: With JavaScript__

With JavaScript, after reading the data before the table (the page metadata and page heading), NVDA recites the table has having __6 rows and 3 columns__.

Here is a partial "transcript" of the page with JavaScript enabled and when the table is viewed on a Desktop device:

> `Responsive Accessible Table`
`Main Landmark heading level 1 Responsive and Accessible Table that works without JavaScript`
`Region table with 6 rows and 3 columns caption World Leaders and their Currencies`

> `Row 1 Column1 Name`

> `Column2 Country`

> `Column3 Currency`
> `Row 2 Name Column1 Boris Johnson`

> `Country Column2 Britain`
> `Currency Column3 Pound`

> `Row 3 Name Column1 Donald Trump`

> `Country Column2 U.S.A.`

> `Currency Column3 Dollar`

On a mobile viewport, NVDA reads the table has having __5 rows and 3 columns__. The reason for the variation of row number is that the first row is hidden using `display: none`.

The code below hides it therefore, it's not available to screen readers:

```css
@media screen and (max-width: 37em), print and (max-width: 5in) {
    .js-version th,
    .js-version tr:first-of-type {
        display: none;
    }
}
```

The [`ResponsiveCellHeaders`](https://github.com/ziizium/responsive-accessible-table/blob/main/responsivetableroselli.js#L1) function does a lot of heavy lifting to make the table accessible on a mobile viewport.

In addition, the tabular data is read differently due to the rearrangement and modification of the table to fit the mobile viewport:

> `Row 1 column 1 Name Boris Johnson`

> `Column 2 Country Britain`

> `Column 3 Currency Pound`

> `Row 2 Column 1 Name Donald Trump`

> `Column 2 Country U.S.A.`

> `Column 3 Currency Dollar`

The main difference is that the screen reader reads the column number before the column data as it's seen on screen.

## __Conclusion__

In this article you've learned how to create a responsive and accessible data table but you'll have to do more work with the arrangement on mobile viewport when the table is complex than what's shown here.

_Did you find a typo or an error? Let me know in the comments. Thank you._