Accessibility

Simplified WCAG guidance

WCAG 2.2 – Levels A and AA only, with dev notes.

Responsive table

A table that not only scrolls horizontally when the content exceeds screen width, but also collapses to display cells vertically at smaller viewports.

Example

The following comparison table may be squeezed by a handle on the bottom right.

This example uses both media queries (screen width) and container queries to adapt content.

Card Careers Account, the different ways we can help, and how they compare
Can be used if you: Carers Card Third party access General Power of Attorney Lasting Power of Attorney Court of Protection

Just need help with the small things, like shopping or getting cash.

Are physically ill, injured or disabled.

Need a little help with looking after your day-to-day banking, for a shorter period of time, but you don't want someone to make decisions for you.

You will be abroad, and won't have access to your account (for example, travelling).

Are preparing for when you'll be unable to make decisions, or want someone to start looking after all of your finances.

No longer have the mental capacity to make decisions, and someone needs to do this for you.

Features

The code

HTML
HTML

  <!-- NOTE: Roles are explicitly stated on table elements because at mobile sizes the elements have their default roles overwritten by the CSS -->
  <!-- Use either a figure or a div with role="region" to contain the table and provide overflow scolling -->  
  <figure class="responsive_wrap" aria-labelledby="table-caption">
    <table class="responsive_table">
      <caption id="table-caption" role="caption">Brief description of what the table contains</caption>
      <thead>
        <tr>
          <th scope="col">1st column header</th>
          <th scope="col">2nd column header</th>
          <th scope="col">3rd column header</th>
          <th scope="col">4th column header</th>
          <th scope="col">5th column header</th>
        </tr>
      </thead>
      <tbody role="rowgroup">
        <tr role="row">
          <th role="rowheader" scope="row" data-header="1st column header">
            <p>1st row heading</p>
          </th>
          <td role="cell" class="icon" data-header="2nd column header">
            <!-- Use inline SVG rather than PNG for icons, colour may be changed by CSS for instance when using dark mode. -->
            <svg aria-label="Yes" class="svg-tick" width="30" height="25" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 25"><path d="M11.8 17.3 24.7 1a3 3 0 0 1 5.1 1c.4 1 .2 2.2-.5 3L14.3 24a3 3 0 0 1-4.4.2l-9-9.4c-.7-.8-1-2-.8-3a3 3 0 0 1 2.2-2.3 3 3 0 0 1 2.9.9l6.6 7Z"/></svg>
          </td>
          <td role="cell" class="icon" data-header="3rd column header">
            <svg aria-label="No" class="svg-dash" width="30" height="25" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 25"><path id="dash" d="M5.8 14.9c0-1.6.2-3.2.5-4.8h17.8c0 1.1-.2 2.7-.5 4.8H5.8Z"/></svg>
          </td>
          <td role="cell" class="icon" data-header="4th column header">
            <svg aria-label="No" class="svg-dash" width="30" height="25" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 25"><path id="dash" d="M5.8 14.9c0-1.6.2-3.2.5-4.8h17.8c0 1.1-.2 2.7-.5 4.8H5.8Z"/></svg>
          </td>
          <td role="cell" class="icon" data-header="5th column header">
            <svg aria-label="No" class="svg-dash" width="30" height="25" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 25"><path id="dash" d="M5.8 14.9c0-1.6.2-3.2.5-4.8h17.8c0 1.1-.2 2.7-.5 4.8H5.8Z"/></svg>
          </td>
        </tr>
        <tr role="row">
          …
        </tr>
        …
      </tbody>
    </table>
  </figure>
CSS
CSS
/* Desktop */

/* Table container becomes horizontally scrollable if overflowed */
.responsive_wrap {
  max-width: 100%;
  overflow-x: auto;

  /* Could possibly use container queries, rather than media queries, but depends upon support */
  container-type: inline-size;
  container-name: table_wrap;
}
* + .responsive_wrap {
  margin: 2em 0; /* Optional, follow style guide */
}

.responsive_table {

  /* Insert colours in from the global styles. */
  --_table-thead-bg-color: #f0f0f0;
  --_table-thead-td-border-color: transparent;
  
  --_table-tr-border-color: #CEDEE7;
  --_table-tr-bg-color: transparent;
  --_table-tr-bg-color-odd: #fff;
  --_table-tr-bg-color-even: #F5F9FB;
  
  --_table-td-border-color: transparent;

  border-collapse: collapse;
  margin: 0;
  color: #000;
}

.responsive_table caption {
  text-align: left;
  font-style: italic; /* Optional, dependent on style guide */
}

.responsive_table thead {
  background-color: var(--_table-thead-bg-color, transparent);
}
.responsive_table thead th {
  line-height: 1.3;
}

/* Table row striping for readability */
.responsive_table tbody tr:nth-child(even) {
  background-color: var(--_table-tr-bg-color-even, transparent);
}
.responsive_table tbody tr:nth-child(odd) {
  background-color: var(--_table-tr-bg-color-odd, transparent);
}

/* Row and Cell borders */
.responsive_table tr {
  border-bottom: 1px solid var(--_table-tr-border-color, #ccc);
}
/* Vertical bars, if used at all, should be very subtle to not interfere with row readability */
.responsive_table thead th + th {
  border-left: 1px solid var(--_table-thead-td-border-color, transparent);
}
.responsive_table td:not([scope=row]) {
  border-left: 1px solid var(--_table-td-border-color, #ccc);
}

/* Larger cell padding at desktop/tablet sizes */
.responsive_table th,
.responsive_table td {
  padding: 8px; /* Optional, check style guide */
}
@media (min-width: 50em) {
  .responsive_table th,
  .responsive_table td {
    padding: 16px; /* Optional, check style guide */
  }
}

.responsive_table [scope=col] {
  text-align: left;
/*   vertical-align: bottom; /* Optional, check style guide */
}
.responsive_table [scope=row] {
  font-weight: normal; /* Optional, check style guide */
  text-align: left; /* Optional, check style guide */
}

/* Text cells must be left aligned, icons may be centred and numbers right aligned. */
.responsive_table td {
  text-align: left; /* Optional, check style guide */
}
td.icon {
  text-align: center;
}
td.number {
  text-align: right;
}


/* Mobile */

/* 40em (640px @ 16px font-size) for this specific table */
@media (max-width: 40em) {

  /* Overides default roles */
  .responsive_table,
  .responsive_table tbody,
  .responsive_table tr,
  .responsive_table th,
  .responsive_table td {
    display: block;
  }
  .responsive_table thead {
    display: none;
  }

  .responsive_table {
    border: none; /* Optional, check style guide */
  }
  .responsive_table caption {
    width: 100%;
    padding: 8px; /* Optional, check style guide */
  }
  .responsive_table [role=rowheader] {
    background-color: var(--_table-thead-bg-color, transparent);
    font-weight: bold;
  }
  .responsive_table tr + tr {
    margin-top: 2rem; /* Optional, check style guide */
  }
  .responsive_table td:not([scope="row"]) {
    border: none;
  }
  .responsive_table th {
    padding: 8px;
  }
  .responsive_table td {
    padding: 0 8px;
    display: block;
    text-align: left;
  }
  .responsive_table td {
    display: grid;
    /* 13em is a magic number, places title in a fixed column. If too small or too large the table will still display responsively */
    grid-template-columns: minmax(var(--mobile-width, 13em), 15em) auto;
    grid-template-columns: clamp(200px, 50vw, 13em) auto;
    align-items: center;
    grid-gap: 0.5em 1em;
  }
  .responsive_table [scope=row]:first-child {
    display: block;
    line-height: 1.5;
  }
  .responsive_table th::before,
  .responsive_table td::before {
    content: attr(data-header);
    display: block;
    font-weight: normal;
    line-height: 1.3;
  }
  
}

Settings

Guidelines

Data tables are a rare example of when it is better to code the desktop view first, then adjust for mobile.