top of page

How To Build Accessible HTML Tables

When building for the web, we want to ensure users of any ability are able to do whatever task they came to our site for. This could be buying something, checking the weather, changing their password, or even deleting their account.

Whatever it is, we want to get rid of any friction that might be there to give them the best user experience possible. At the end of the day, accessibility is about user experience and ensuring a consistent user experience across user abilities.

What we’re building

Data tables are one of those touchy web components that can be done a million different ways. We aren’t going to focusing on things like pagination, sorting, etc. We’re making a basic table that, at its core, applies to whatever implementation of a data table you or your company needs.

We’ll make a simple table to display some data from the Harry Potter movie franchise (I’m a Gryffindor, what are you). We’ll show each of the 8 movie’s title, release date, production budget, and opening weekend revenue. I grabbed this data from here. Again, what we won’t be doing is any sorting, filtering, etc.

As with any web component, we want to start with proper HTML semantics. Many basic accessibility issues can be fixed by going back to good semantic markup. Even something as simple as replacing <div> tags (masquerading as buttons or whatever) with the proper HTML element can go a long way to making your code more readable and accessible.

The HTML structure for a data table is pretty straightforward. I’ve illustrated this below:

Getting started

This is what we will start with here – it’s very rough, but it gives the basic HTML markup. Immediately, we should add the scope attribute to our <th> elements to let any screen readers know to treat or headers as columns. They should look like this:

        <th scope="col">Movie title</th>
        <th scope="col">Release date</th>
        <th scope="col">Production budget</th>
        <th scope="col">Opening weekend</th>

Side note: if you wanted to treat each movie title as a header for the row (just a different way to organize the data), you could do: <th scope="row">Harry Potter and the Half-Blood Prince</th>. Read more about the scope attribute here.

Making it responsive

Next, let’s make this more mobile-friendly. This can be a huge obstacle to any team, so make sure to get on the same page with your designer as to behavior in different viewports. We can be lazy here and get 80% there with a couple of lines of CSS (you should explore this further to fit your needs):

th {
    border-collapse: collapse;
    text-align: left;
table {
    width: 100%;
    margin: 24px auto;
    table-layout: auto;


You might notice that I’ve started you with a font-size of 1em. This will respect any user preferences that may have been set. In general, you should avoid using fonts smaller than 14px as much as possible on the web – no one should have to squint to read your content.

Let’s bring attention to the <caption> that is serving as our title by adding some weight, padding, and increasing the size:

caption {
    font-size: 2.5em;
    font-weight: 700;
    padding: .5em 0;

We can also quickly add a zebra effect to the table rows – this can make it easier for your eyes to track along a row. One gotcha with adding this effect is making sure your contrast ratio between the font-color and the background-color are accessible. WebAIM offers a great resource to check your ratios and you can now check this directly in Chrome DevTools.

tr:nth-child(even) {
    background-color: rgba(238, 186, 48, 0.4);

Now we can differentiate our <th> cells by adding a nice background-color in Gryffindor red and getting rid of the border by matching the color:

th {
    padding: 1em .75em;
    color: #FFFFFF;
    background-color: #740001;
    border: 1px solid #740001;

One last readability issue you might see (there are differing opinions on this) is that our cells representing monetary values could be right-aligned. This is easily achieved by targeting our <td>‘s in our columns with a class, we’ll put class="money" on each of these. Then in our CSS, add the class:

.money {
    text-align: right;

In the end, you should have something like the following Pen. Feel free to fork it and make it your own.


When it comes to building accessible web components you should do the following:

  • Check back with the docs at MDN to ensure you’re using good, semantic HTML

  • Take a look at the WCAG 2.0 guidelines and familiarize yourself

  • Use extensions freely available to you, like Funkify and Lighthouse

  • Use your site or application with an actual screen reader

  • Check color contrast throughout your interface using Sim Daltonism, DevTools, etc.

  • Realize accessibility is more than just a checklist, it’s a mindset

Source: Codewalk

The Tech Platform


Recent Posts

See All
bottom of page