Skip to main content

Content presentation Table

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

Basic tables

2 column table

Open this example in a new tab: table basic
<table class="nhsuk-table">
  <caption class="nhsuk-table__caption">
    Skin symptoms and possible causes
  </caption>
  <thead class="nhsuk-table__head">
    <tr class="nhsuk-table__row">
      <th scope="col" class="nhsuk-table__header">
        Skin symptoms
      </th>
      <th scope="col" class="nhsuk-table__header">
        Possible cause
      </th>
    </tr>
  </thead>
  <tbody class="nhsuk-table__body">
    <tr 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 class="nhsuk-table__row">
      <td class="nhsuk-table__cell">
        Itchy, dry, cracked, sore
      </td>
      <td class="nhsuk-table__cell">
        Eczema
      </td>
    </tr>
    <tr class="nhsuk-table__row">
      <td class="nhsuk-table__cell">
        Itchy blisters
      </td>
      <td class="nhsuk-table__cell">
        Shingles, chickenpox
      </td>
    </tr>
  </tbody>
</table>
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.

Primary options
Name Type Description
id string The ID of the table.
rows array Required. Array of table rows and cells. See macro options for rows.
head array Array of table head cells. See macro options for head.
caption string Caption text.
captionClasses string Classes for caption text size. Classes to add to the table caption, for example "nhsuk-table__caption--l".
captionSize string Size of the caption – "s", "m", "l" or "xl".
firstCellIsHeader boolean If set to true, first cell in table row will be a TH instead of a TD.
responsive boolean If set to true, responsive table classes will be applied.
card object Can be used to wrap a card around the table component. If any of these options are present, a card will wrap around the table. See macro options for card.
classes string Classes to add to the table container.
attributes object HTML attributes (for example data attributes) to add to the table container.
Options for rows array objects
Name Type Description
text string Required. If html is set, this is not required. Text for cells in table rows. If html is provided, the text argument will be ignored.
html string Required. If text is set, this is not required. HTML for cells in table rows. If html is provided, the text argument will be ignored.
header string Header text for cells in responsive table rows only.
format string Specify format of a cell. Currently we only use "numeric".
colspan integer Specify how many columns a cell extends.
rowspan integer Specify how many rows a cell extends.
Options for head array objects
Name Type Description
text string If html is set, this is not required. Text for table head cells. If html is provided, the text argument will be ignored.
html string If text is set, this is not required. HTML for table head cells. If html is provided, the text argument will be ignored.
format string Specify format of a cell. Currently we only use "numeric".
colspan integer Specify how many columns a cell extends.
rowspan integer Specify how many rows a cell extends.
{% from "tables/macro.njk" import table %}

{{ table({
  caption: "Skin symptoms and possible causes",
  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"
      }
    ]
  ]
}) }}

3 or more column table

If you have numeric data, right align the column header and cells to make it easier to compare numbers.

Open this example in a new tab: table 3 column
<table class="nhsuk-table">
  <caption class="nhsuk-table__caption">
    Prescription prepayment certificate (PPC) charges
  </caption>
  <thead class="nhsuk-table__head">
    <tr class="nhsuk-table__row">
      <th scope="col" class="nhsuk-table__header">
        Item
      </th>
      <th scope="col" class="nhsuk-table__header nhsuk-table__header--numeric">
        Current charge
      </th>
      <th scope="col" class="nhsuk-table__header nhsuk-table__header--numeric">
        New charge
      </th>
    </tr>
  </thead>
  <tbody class="nhsuk-table__body">
    <tr class="nhsuk-table__row">
      <th scope="row" class="nhsuk-table__header">
        3-month
      </th>
      <td class="nhsuk-table__cell nhsuk-table__cell--numeric">
        £31.25
      </td>
      <td class="nhsuk-table__cell nhsuk-table__cell--numeric">
        £32.05
      </td>
    </tr>
    <tr class="nhsuk-table__row">
      <th scope="row" class="nhsuk-table__header">
        12-month
      </th>
      <td class="nhsuk-table__cell nhsuk-table__cell--numeric">
        £111.60
      </td>
      <td class="nhsuk-table__cell nhsuk-table__cell--numeric">
        £114.50
      </td>
    </tr>
    <tr class="nhsuk-table__row">
      <th scope="row" class="nhsuk-table__header">
        HRT
      </th>
      <td class="nhsuk-table__cell nhsuk-table__cell--numeric">
        £19.30
      </td>
      <td class="nhsuk-table__cell nhsuk-table__cell--numeric">
        £19.80
      </td>
    </tr>
  </tbody>
</table>
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.

Primary options
Name Type Description
id string The ID of the table.
rows array Required. Array of table rows and cells. See macro options for rows.
head array Array of table head cells. See macro options for head.
caption string Caption text.
captionClasses string Classes for caption text size. Classes to add to the table caption, for example "nhsuk-table__caption--l".
captionSize string Size of the caption – "s", "m", "l" or "xl".
firstCellIsHeader boolean If set to true, first cell in table row will be a TH instead of a TD.
responsive boolean If set to true, responsive table classes will be applied.
card object Can be used to wrap a card around the table component. If any of these options are present, a card will wrap around the table. See macro options for card.
classes string Classes to add to the table container.
attributes object HTML attributes (for example data attributes) to add to the table container.
Options for rows array objects
Name Type Description
text string Required. If html is set, this is not required. Text for cells in table rows. If html is provided, the text argument will be ignored.
html string Required. If text is set, this is not required. HTML for cells in table rows. If html is provided, the text argument will be ignored.
header string Header text for cells in responsive table rows only.
format string Specify format of a cell. Currently we only use "numeric".
colspan integer Specify how many columns a cell extends.
rowspan integer Specify how many rows a cell extends.
Options for head array objects
Name Type Description
text string If html is set, this is not required. Text for table head cells. If html is provided, the text argument will be ignored.
html string If text is set, this is not required. HTML for table head cells. If html is provided, the text argument will be ignored.
format string Specify format of a cell. Currently we only use "numeric".
colspan integer Specify how many columns a cell extends.
rowspan integer Specify how many rows a cell extends.
{% from "tables/macro.njk" import table %}

{{ table({
  caption: "Prescription prepayment certificate (PPC) charges",
  firstCellIsHeader: true,
  head: [
    {
      text: "Item"
    },
    {
      text: "Current charge",
      format: "numeric"
    },
    {
      text: "New charge",
      format: "numeric"
    }
  ],
  rows: [
    [
      {
        text: "3-month"
      },
      {
        text: "£31.25",
        format: "numeric"
      },
      {
        text: "£32.05",
        format: "numeric"
      }
    ],
    [
      {
        text: "12-month"
      },
      {
        text: "£111.60",
        format: "numeric"
      },
      {
        text: "£114.50",
        format: "numeric"
      }
    ],
    [
      {
        text: "HRT"
      },
      {
        text: "£19.30",
        format: "numeric"
      },
      {
        text: "£19.80",
        format: "numeric"
      }
    ]
  ]
}) }}

When not to use a basic table

Do not use a basic table:

  • to lay out content on a page – use the grid system instead
  • if your table content becomes squashed and hard to read on small screens – use a responsive table instead

Responsive table

This table has a responsive layout. On large screens it displays as a 3 column table. However, on small screens it stacks vertically.

Use a responsive table when your table becomes squashed and hard to read on small screens, 768px and smaller.

Open this example in a new tab: table responsive
<table class="nhsuk-table-responsive" role="table">
  <caption class="nhsuk-table__caption">
    Ibuprofen liquid dosages for children
  </caption>
  <thead class="nhsuk-table__head" role="rowgroup">
    <tr class="nhsuk-table__row" role="row">
      <th scope="col" class="nhsuk-table__header nhsuk-u-width-one-half" role="columnheader">
        Age
      </th>
      <th scope="col" class="nhsuk-table__header nhsuk-u-width-one-quarter" role="columnheader">
        How much?
      </th>
      <th scope="col" class="nhsuk-table__header nhsuk-u-width-one-quarter" role="columnheader">
        How often?
      </th>
    </tr>
  </thead>
  <tbody class="nhsuk-table__body">
    <tr class="nhsuk-table__row" role="row">
      <td class="nhsuk-table__cell" role="cell">
        <span class="nhsuk-table-responsive__heading" aria-hidden="true">Age </span>3 to 5 months (weighing more than 5kg)
      </td>
      <td class="nhsuk-table__cell" role="cell">
        <span class="nhsuk-table-responsive__heading" aria-hidden="true">How much? </span>2.5ml
      </td>
      <td class="nhsuk-table__cell" role="cell">
        <span class="nhsuk-table-responsive__heading" aria-hidden="true">How often? </span>Max 3 times in 24 hours
      </td>
    </tr>
    <tr class="nhsuk-table__row" role="row">
      <td class="nhsuk-table__cell" role="cell">
        <span class="nhsuk-table-responsive__heading" aria-hidden="true">Age </span>6 to 11 months
      </td>
      <td class="nhsuk-table__cell" role="cell">
        <span class="nhsuk-table-responsive__heading" aria-hidden="true">How much? </span>2.5l
      </td>
      <td class="nhsuk-table__cell" role="cell">
        <span class="nhsuk-table-responsive__heading" aria-hidden="true">How often? </span>Max 3 to 4 times in 24 hours
      </td>
    </tr>
    <tr class="nhsuk-table__row" role="row">
      <td class="nhsuk-table__cell" role="cell">
        <span class="nhsuk-table-responsive__heading" aria-hidden="true">Age </span>1 to 3 years
      </td>
      <td class="nhsuk-table__cell" role="cell">
        <span class="nhsuk-table-responsive__heading" aria-hidden="true">How much? </span>5ml
      </td>
      <td class="nhsuk-table__cell" role="cell">
        <span class="nhsuk-table-responsive__heading" aria-hidden="true">How often? </span>Max 3 times in 24 hours
      </td>
    </tr>
  </tbody>
</table>
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.

Primary options
Name Type Description
id string The ID of the table.
rows array Required. Array of table rows and cells. See macro options for rows.
head array Array of table head cells. See macro options for head.
caption string Caption text.
captionClasses string Classes for caption text size. Classes to add to the table caption, for example "nhsuk-table__caption--l".
captionSize string Size of the caption – "s", "m", "l" or "xl".
firstCellIsHeader boolean If set to true, first cell in table row will be a TH instead of a TD.
responsive boolean If set to true, responsive table classes will be applied.
card object Can be used to wrap a card around the table component. If any of these options are present, a card will wrap around the table. See macro options for card.
classes string Classes to add to the table container.
attributes object HTML attributes (for example data attributes) to add to the table container.
Options for rows array objects
Name Type Description
text string Required. If html is set, this is not required. Text for cells in table rows. If html is provided, the text argument will be ignored.
html string Required. If text is set, this is not required. HTML for cells in table rows. If html is provided, the text argument will be ignored.
header string Header text for cells in responsive table rows only.
format string Specify format of a cell. Currently we only use "numeric".
colspan integer Specify how many columns a cell extends.
rowspan integer Specify how many rows a cell extends.
Options for head array objects
Name Type Description
text string If html is set, this is not required. Text for table head cells. If html is provided, the text argument will be ignored.
html string If text is set, this is not required. HTML for table head cells. If html is provided, the text argument will be ignored.
format string Specify format of a cell. Currently we only use "numeric".
colspan integer Specify how many columns a cell extends.
rowspan integer Specify how many rows a cell extends.
{% from "tables/macro.njk" import table %}

{{ table({
  caption: "Ibuprofen liquid dosages for children",
  responsive: true,
  head: [
    {
      text: "Age",
      classes: "nhsuk-u-width-one-half"
    },
    {
      text: "How much?",
      classes: "nhsuk-u-width-one-quarter"
    },
    {
      text: "How often?",
      classes: "nhsuk-u-width-one-quarter"
    }
  ],
  rows: [
    [
      {
        header: "Age",
        text: "3 to 5 months (weighing more than 5kg)"
      },
      {
        header: "How much?",
        text: "2.5ml"
      },
      {
        header: "How often?",
        text: "Max 3 times in 24 hours"
      }
    ],
    [
      {
        header: "Age",
        text: "6 to 11 months"
      },
      {
        header: "How much?",
        text: "2.5l"
      },
      {
        header: "How often?",
        text: "Max 3 to 4 times in 24 hours"
      }
    ],
    [
      {
        header: "Age",
        text: "1 to 3 years"
      },
      {
        header: "How much?",
        text: "5ml"
      },
      {
        header: "How often?",
        text: "Max 3 times in 24 hours"
      }
    ]
  ]
}) }}

When not to use a responsive table

Do not use a responsive table:

  • to lay out content on a page – use the grid system instead
  • if your content is easier to read and understand on a small screen in a non-responsive layout – use a basic table instead

Using word-breaks in a table

To avoid very long words, such as email addresses, breaking the layout of a table, add the nhsuk-u-text-break-word class.

Open this example in a new tab: table word break
<table class="nhsuk-table">
  <caption class="nhsuk-table__caption">
    Users
  </caption>
  <thead class="nhsuk-table__head">
    <tr class="nhsuk-table__row">
      <th scope="col" class="nhsuk-table__header">
        Name
      </th>
      <th scope="col" class="nhsuk-table__header">
        Email address
      </th>
    </tr>
  </thead>
  <tbody class="nhsuk-table__body">
    <tr class="nhsuk-table__row">
      <td class="nhsuk-table__cell nhsuk-u-text-break-word">
        Aleksandrina Featherstonehaugh-Whitehead
      </td>
      <td class="nhsuk-table__cell nhsuk-u-text-break-word">
        aleksandrina.featherstonehaughwhitehead23@folkestonepharmacy.test.com
      </td>
    </tr>
  </tbody>
</table>
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.

Primary options
Name Type Description
id string The ID of the table.
rows array Required. Array of table rows and cells. See macro options for rows.
head array Array of table head cells. See macro options for head.
caption string Caption text.
captionClasses string Classes for caption text size. Classes to add to the table caption, for example "nhsuk-table__caption--l".
captionSize string Size of the caption – "s", "m", "l" or "xl".
firstCellIsHeader boolean If set to true, first cell in table row will be a TH instead of a TD.
responsive boolean If set to true, responsive table classes will be applied.
card object Can be used to wrap a card around the table component. If any of these options are present, a card will wrap around the table. See macro options for card.
classes string Classes to add to the table container.
attributes object HTML attributes (for example data attributes) to add to the table container.
Options for rows array objects
Name Type Description
text string Required. If html is set, this is not required. Text for cells in table rows. If html is provided, the text argument will be ignored.
html string Required. If text is set, this is not required. HTML for cells in table rows. If html is provided, the text argument will be ignored.
header string Header text for cells in responsive table rows only.
format string Specify format of a cell. Currently we only use "numeric".
colspan integer Specify how many columns a cell extends.
rowspan integer Specify how many rows a cell extends.
Options for head array objects
Name Type Description
text string If html is set, this is not required. Text for table head cells. If html is provided, the text argument will be ignored.
html string If text is set, this is not required. HTML for table head cells. If html is provided, the text argument will be ignored.
format string Specify format of a cell. Currently we only use "numeric".
colspan integer Specify how many columns a cell extends.
rowspan integer Specify how many rows a cell extends.
{% from "tables/macro.njk" import table %}

{{ table({
  caption: "Users",
  head: [
    {
      text: "Name"
    },
    {
      text: "Email address"
    }
  ],
  rows: [
    [
      {
        text: "Aleksandrina Featherstonehaugh-Whitehead",
        classes: "nhsuk-u-text-break-word"
      },
      {
        text: "aleksandrina.featherstonehaughwhitehead23@folkestonepharmacy.test.com",
        classes: "nhsuk-u-text-break-word"
      }
    ]
  ]
}) }}

Find out more about word-breaks, with or without a hyphen, in breaking up long words in the typography section.

Displaying missing data

Do not leave empty cells in your table. The only exception can be the top left cell. If you have missing data, include some short text to explain why it's missing, such as:

  • "No data"
  • "Not applicable"
  • "Not known"

To distinguish the text from other table content, use the nhsuk-u-secondary-text-colour modifier class to make it dark grey.

Open this example in a new tab: table missing data
<table class="nhsuk-table">
  <caption class="nhsuk-table__caption">
    Vaccinations given
  </caption>
  <thead class="nhsuk-table__head">
    <tr class="nhsuk-table__row">
      <th scope="col" class="nhsuk-table__header">
        Date
      </th>
      <th scope="col" class="nhsuk-table__header">
        Vaccine
      </th>
      <th scope="col" class="nhsuk-table__header">
        Product
      </th>
    </tr>
  </thead>
  <tbody class="nhsuk-table__body">
    <tr class="nhsuk-table__row">
      <td class="nhsuk-table__cell">
        10 July 2024
      </td>
      <td class="nhsuk-table__cell">
        RSV
      </td>
      <td class="nhsuk-table__cell">
        Abrysvo
      </td>
    </tr>
    <tr class="nhsuk-table__row">
      <td class="nhsuk-table__cell">
        6 September 2023
      </td>
      <td class="nhsuk-table__cell">
        Flu
      </td>
      <td class="nhsuk-table__cell nhsuk-u-secondary-text-colour">
        No data
      </td>
    </tr>
  </tbody>
</table>
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.

Primary options
Name Type Description
id string The ID of the table.
rows array Required. Array of table rows and cells. See macro options for rows.
head array Array of table head cells. See macro options for head.
caption string Caption text.
captionClasses string Classes for caption text size. Classes to add to the table caption, for example "nhsuk-table__caption--l".
captionSize string Size of the caption – "s", "m", "l" or "xl".
firstCellIsHeader boolean If set to true, first cell in table row will be a TH instead of a TD.
responsive boolean If set to true, responsive table classes will be applied.
card object Can be used to wrap a card around the table component. If any of these options are present, a card will wrap around the table. See macro options for card.
classes string Classes to add to the table container.
attributes object HTML attributes (for example data attributes) to add to the table container.
Options for rows array objects
Name Type Description
text string Required. If html is set, this is not required. Text for cells in table rows. If html is provided, the text argument will be ignored.
html string Required. If text is set, this is not required. HTML for cells in table rows. If html is provided, the text argument will be ignored.
header string Header text for cells in responsive table rows only.
format string Specify format of a cell. Currently we only use "numeric".
colspan integer Specify how many columns a cell extends.
rowspan integer Specify how many rows a cell extends.
Options for head array objects
Name Type Description
text string If html is set, this is not required. Text for table head cells. If html is provided, the text argument will be ignored.
html string If text is set, this is not required. HTML for table head cells. If html is provided, the text argument will be ignored.
format string Specify format of a cell. Currently we only use "numeric".
colspan integer Specify how many columns a cell extends.
rowspan integer Specify how many rows a cell extends.
{% from "tables/macro.njk" import table %}

{{ table({
  caption: "Vaccinations given",
  head: [
    {
      text: "Date"
    },
    {
      text: "Vaccine"
    },
    {
      text: "Product"
    }
  ],
  rows: [
    [
      {
        text: "10 July 2024"
      },
      {
        text: "RSV"
      },
      {
        text: "Abrysvo"
      }
    ],
    [
      {
        text: "6 September 2023"
      },
      {
        text: "Flu"
      },
      {
        text: "No data",
        classes: "nhsuk-u-secondary-text-colour"
      }
    ]
  ]
}) }}

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.

Style table captions to match the visual hierarchy of your page's content. If using Nunjucks, use the captionSize macro option. In HTML add the nhsuk-table__caption--l class. You can use sizes s, m, l, xl.

Table headers

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

Research

Basic tables

These tables tested well with users of health information on the NHS website.

Responsive table

This table was tested at HM Revenue & Customs.

Table with panel

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

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.

Feed back or share insights on GitHub

Read more about how to feed back or share insights.

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

Updated: August 2025