Content presentation - Table

Use a table to make it easier for users to compare and scan information.

2 column table

Open this default table example in new window
Copy default table code
<table class="nhsuk-table">
  <caption class="nhsuk-table__caption">Skin symptoms and possible causes</caption>
  <thead role="rowgroup" class="nhsuk-table__head">
    <tr role="row">
      <th role="columnheader" class="" scope="col">
        Skin symptoms
      </th>
      <th role="columnheader" class="" scope="col">
        Possible cause
      </th>
    </tr>
  </thead>
  <tbody class="nhsuk-table__body">
    <tr role="row" class="nhsuk-table__row">
      <td class="nhsuk-table__cell">Blisters on lips or around the mouth</td>
      <td class="nhsuk-table__cell ">cold sores</td>
    </tr>
    <tr role="row" class="nhsuk-table__row">
      <td class="nhsuk-table__cell">Itchy, dry, cracked, sore</td>
      <td class="nhsuk-table__cell ">eczema</td>
    </tr>
    <tr role="row" class="nhsuk-table__row">
      <td class="nhsuk-table__cell">Itchy blisters</td>
      <td class="nhsuk-table__cell ">shingles, chickenpox</td>
    </tr>
  </tbody>
</table>
Close default table code
Nunjucks macro options

Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text.

Some options are required for the macro to work; these are marked as "Required" in the option description.

If you're using Nunjucks macros in production with "html" options, or ones ending with "html", you must sanitise the HTML to protect against cross-site scripting exploits.

Nunjucks arguments for default table
Name Type Required Description
Name rows Type array Required true Description Array of table rows and cells.
Name rows[].text Type string Required true Description If `html` is set, this is not required. Text for cells in table rows. If `html` is provided, the `text` argument will be ignored.
Name rows[].html Type string Required true Description If `text` is set, this is not required. HTML for cells in table rows. If `html` is provided, the `text` argument will be ignored.
Name rows[].format Type string Required false Description Specify format of a cell. Currently we only use "numeric".
Name rows[].colspan Type integer Required false Description Specify how many columns a cell extends.
Name rows[].rowspan Type integer Required false Description Specify how many rows a cell extends.
Name head Type array Required false Description Array of table head cells.
Name head[].text Type string Required false Description If `html` is set, this is not required. Text for table head cells. If `html` is provided, the `text` argument will be ignored.
Name head[].html Type string Required false Description If `text` is set, this is not required. HTML for table head cells. If `html` is provided, the `text` argument will be ignored.
Name head[].format Type string Required false Description Specify format of a cell. Currently we only use "numeric".
Name head[].colspan Type integer Required false Description Specify how many columns a cell extends.
Name head[].rowspan Type integer Required false Description Specify how many rows a cell extends.
Name heading Type string Required false Description Heading/label of the panel if the panel argument is set to true.
Name headingLevel Type integer Required false Description Optional heading level for the heading. Default: 3.
Name caption Type string Required false Description Caption text.
Name captionClasses Type string Required false Description Classes for caption text size. Classes should correspond to the available typography heading classes.
Name firstCellIsHeader Type boolean Required false Description If set to true, first cell in table row will be a TH instead of a TD.
Name responsive Type boolean Required false Description If set to true, responsive table classes will be applied.
Name tableClasses Type string Required false Description Classes to add to the table container.
Name attributes Type object Required false Description HTML attributes (for example data attributes) to add to the table container.
Copy default table code
{% from 'tables/macro.njk' import table %}

{{ table({
  panel: false,
  caption: "Skin symptoms and possible causes",
  firstCellIsHeader: false,
  head: [
    {
      text: "Skin symptoms"
    },
    {
      text: "Possible cause"
    }
  ],
  rows: [
    [
      {
        text: "Blisters on lips or around the mouth"
      },
      {
        text: "cold sores"
      }
    ],
    [
      {
        text: "Itchy, dry, cracked, sore"
      },
      {
        text: "eczema"
      }
    ],
    [
      {
        text: "Itchy blisters"
      },
      {
        text: "shingles, chickenpox"
      }
    ]
  ]
}) }}
Close default table code

When not to use a 2 column table

Do not use a 2 column table:

3 or more column table

On large screens this table looks like a 2 column table. However, on smaller screens it collapses.

Open this responsive table example in new window
Copy responsive table code
<table role="table" class="nhsuk-table-responsive">
  <caption class="nhsuk-table__caption">Ibuprofen tablet dosages for children</caption>
  <thead role="rowgroup" class="nhsuk-table__head">
    <tr role="row">
      <th role="columnheader" class="" scope="col">
        Age
      </th>
      <th role="columnheader" class="" scope="col">
        How much
      </th>
      <th role="columnheader" class="" scope="col">
        How often
      </th>
    </tr>
  </thead>
  <tbody class="nhsuk-table__body">
    <tr role="row" class="nhsuk-table__row">
      <td role="cell" class="nhsuk-table__cell">
        <span class="nhsuk-table-responsive__heading">Age </span>7 to 9 years
      </td>
      <td role="cell" class="nhsuk-table__cell">
        <span class="nhsuk-table-responsive__heading">How much? </span>200mg
      </td>
      <td role="cell" class="nhsuk-table__cell">
        <span class="nhsuk-table-responsive__heading">How often? </span>Max 3 times in 24 hours
      </td>
    </tr>
    <tr role="row" class="nhsuk-table__row">
      <td role="cell" class="nhsuk-table__cell">
        <span class="nhsuk-table-responsive__heading">Age </span>10 to 11 years
      </td>
      <td role="cell" class="nhsuk-table__cell">
        <span class="nhsuk-table-responsive__heading">How much? </span>200mg to 300mg
      </td>
      <td role="cell" class="nhsuk-table__cell">
        <span class="nhsuk-table-responsive__heading">How often? </span>Max 3 times in 24 hours
      </td>
    </tr>
    <tr role="row" class="nhsuk-table__row">
      <td role="cell" class="nhsuk-table__cell">
        <span class="nhsuk-table-responsive__heading">Age </span>12 to 17 years
      </td>
      <td role="cell" class="nhsuk-table__cell">
        <span class="nhsuk-table-responsive__heading">How much? </span>200mg to 400mg
      </td>
      <td role="cell" class="nhsuk-table__cell">
        <span class="nhsuk-table-responsive__heading">How often? </span>Max 3 times in 24 hours
      </td>
    </tr>
  </tbody>
</table>
Close responsive table code
Nunjucks macro options

Use options to customise the appearance, content and behaviour of a component when using a macro, for example, changing the text.

Some options are required for the macro to work; these are marked as "Required" in the option description.

If you're using Nunjucks macros in production with "html" options, or ones ending with "html", you must sanitise the HTML to protect against cross-site scripting exploits.

Nunjucks arguments for responsive table
Name Type Required Description
Name rows Type array Required true Description Array of table rows and cells.
Name rows[].text Type string Required true Description If `html` is set, this is not required. Text for cells in table rows. If `html` is provided, the `text` argument will be ignored.
Name rows[].html Type string Required true Description If `text` is set, this is not required. HTML for cells in table rows. If `html` is provided, the `text` argument will be ignored.
Name rows[].format Type string Required false Description Specify format of a cell. Currently we only use "numeric".
Name rows[].colspan Type integer Required false Description Specify how many columns a cell extends.
Name rows[].rowspan Type integer Required false Description Specify how many rows a cell extends.
Name head Type array Required false Description Array of table head cells.
Name head[].text Type string Required false Description If `html` is set, this is not required. Text for table head cells. If `html` is provided, the `text` argument will be ignored.
Name head[].html Type string Required false Description If `text` is set, this is not required. HTML for table head cells. If `html` is provided, the `text` argument will be ignored.
Name head[].format Type string Required false Description Specify format of a cell. Currently we only use "numeric".
Name head[].colspan Type integer Required false Description Specify how many columns a cell extends.
Name head[].rowspan Type integer Required false Description Specify how many rows a cell extends.
Name heading Type string Required false Description Heading/label of the panel if the panel argument is set to true.
Name headingLevel Type integer Required false Description Optional heading level for the heading. Default: 3.
Name caption Type string Required false Description Caption text.
Name captionClasses Type string Required false Description Classes for caption text size. Classes should correspond to the available typography heading classes.
Name firstCellIsHeader Type boolean Required false Description If set to true, first cell in table row will be a TH instead of a TD.
Name responsive Type boolean Required false Description If set to true, responsive table classes will be applied.
Name tableClasses Type string Required false Description Classes to add to the table container.
Name attributes Type object Required false Description HTML attributes (for example data attributes) to add to the table container.
Copy responsive table code
{% from 'tables/macro.njk' import table %}

{{ table({
  responsive: true,
  panel: false,
  caption: "Ibuprofen tablet dosages for children",
  firstCellIsHeader: false,
  head: [
    {
      text: "Age"
    },
    {
      text: "How much"
    },
    {
      text: "How often"
    }
  ],
  rows: [
    [
      {
        header: "Age",
        text: "7 to 9 years"
      },
      {
        header: "How much?",
        text: "200mg"
      },
      {
        header: "How often?",
        text: "Max 3 times in 24 hours"
      }
    ],
    [
      {
        header: "Age",
        text: "10 to 11 years"
      },
      {
        header: "How much?",
        text: "200mg to 300mg"
      },
      {
        header: "How often?",
        text: "Max 3 times in 24 hours"
      }
    ],
    [
      {
        header: "Age",
        text: "12 to 17 years"
      },
      {
        header: "How much?",
        text: "200mg to 400mg"
      },
      {
        header: "How often?",
        text: "Max 3 times in 24 hours"
      }
    ]
  ]
}) }}
Close responsive table code

When not to use a 3 or more column table

Do not use a 3 or more column table:

How tables work

Accessibility

Follow WebAIM's guidance for tables and

  • give tables captions
  • use the scope attribute to associate the data cells with the appropriate headers
  • let the browser window determine the width of the table whenever possible, to reduce horizontal scrolling

Table captions

Use the <caption> element to describe a table in the same way you would use a heading. A caption helps users find, navigate and understand tables.

Table headers

Use table headers to tell users what the rows and columns represent.

Research

2 column table

This table tested well with users of health information on the NHS website.

3 or more column table

This table was tested at HM Revenue & Customs.

Table with panel

We have also designed a table with a panel. You can see an example in the frontend library. We haven't included it in this list of components yet because it needs more testing.

If you’ve used tables, get in touch to share your user research findings.

Help us improve this guidance

Share insights or feedback and take part in the discussion. We use GitHub as a collaboration space. All the information on it is open to the public.

Read more about how to feedback or share insights.

If you have any questions, get in touch with the service manual team.

Updated: October 2020