Content presentation - Tabs
Experimental

The tabs component lets users navigate between related sections of content, displaying 1 section at a time.

Open this default tabs example in new window
Copy default tabs code
<div class="nhsuk-tabs" data-module="nhsuk-tabs">
  <h2 class="nhsuk-tabs__title">
    Contents
  </h2>

  <ul class="nhsuk-tabs__list">

    <li class="nhsuk-tabs__list-item nhsuk-tabs__list-item--selected">
      <a class="nhsuk-tabs__tab" href="#past-day">
        Past day
      </a>
    </li>

    <li class="nhsuk-tabs__list-item">
      <a class="nhsuk-tabs__tab" href="#past-week">
        Past week
      </a>
    </li>

    <li class="nhsuk-tabs__list-item">
      <a class="nhsuk-tabs__tab" href="#past-month">
        Past month
      </a>
    </li>

    <li class="nhsuk-tabs__list-item">
      <a class="nhsuk-tabs__tab" href="#past-year">
        Past year
      </a>
    </li>

  </ul>

  <div class="nhsuk-tabs__panel" id="past-day">

    <table role="table" class="nhsuk-table-responsive">
      <caption class="nhsuk-table__caption">Past day</caption>
      <thead role="rowgroup" class="nhsuk-table__head">
        <tr role="row">
          <th role="columnheader" class="" scope="col">
            Case manager
          </th>
          <th role="columnheader" class="" scope="col">
            Cases opened
          </th>
          <th role="columnheader" class="" scope="col">
            Cases closed
          </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">Case manager </span>David Francis
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>3
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>0
          </td>
        </tr>
        <tr role="row" class="nhsuk-table__row">
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Case manager </span>Paul Farmer
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>1
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>0
          </td>
        </tr>
        <tr role="row" class="nhsuk-table__row">
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Case manager </span>Rita Patel
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>2
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>0
          </td>
        </tr>
      </tbody>
    </table>

  </div>

  <div class="nhsuk-tabs__panel nhsuk-tabs__panel--hidden" id="past-week">

    <table role="table" class="nhsuk-table-responsive">
      <caption class="nhsuk-table__caption">Past week</caption>
      <thead role="rowgroup" class="nhsuk-table__head">
        <tr role="row">
          <th role="columnheader" class="" scope="col">
            Case manager
          </th>
          <th role="columnheader" class="" scope="col">
            Cases opened
          </th>
          <th role="columnheader" class="" scope="col">
            Cases closed
          </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">Case manager </span>David Francis
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>24
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>18
          </td>
        </tr>
        <tr role="row" class="nhsuk-table__row">
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Case manager </span>Paul Farmer
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>16
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>20
          </td>
        </tr>
        <tr role="row" class="nhsuk-table__row">
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Case manager </span>Rita Patel
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>24
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>27
          </td>
        </tr>
      </tbody>
    </table>

  </div>

  <div class="nhsuk-tabs__panel nhsuk-tabs__panel--hidden" id="past-month">

    <table role="table" class="nhsuk-table-responsive">
      <caption class="nhsuk-table__caption">Past month</caption>
      <thead role="rowgroup" class="nhsuk-table__head">
        <tr role="row">
          <th role="columnheader" class="" scope="col">
            Case manager
          </th>
          <th role="columnheader" class="" scope="col">
            Cases opened
          </th>
          <th role="columnheader" class="" scope="col">
            Cases closed
          </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">Case manager </span>David Francis
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>98
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>95
          </td>
        </tr>
        <tr role="row" class="nhsuk-table__row">
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Case manager </span>Paul Farmer
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>122
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>131
          </td>
        </tr>
        <tr role="row" class="nhsuk-table__row">
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Case manager </span>Rita Patel
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>126
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>142
          </td>
        </tr>
      </tbody>
    </table>

  </div>

  <div class="nhsuk-tabs__panel nhsuk-tabs__panel--hidden" id="past-year">

    <table role="table" class="nhsuk-table-responsive">
      <caption class="nhsuk-table__caption">Past year</caption>
      <thead role="rowgroup" class="nhsuk-table__head">
        <tr role="row">
          <th role="columnheader" class="" scope="col">
            Case manager
          </th>
          <th role="columnheader" class="" scope="col">
            Cases opened
          </th>
          <th role="columnheader" class="" scope="col">
            Cases closed
          </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">Case manager </span>David Francis
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>1380
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>1472
          </td>
        </tr>
        <tr role="row" class="nhsuk-table__row">
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Case manager </span>Paul Farmer
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>1129
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>1083
          </td>
        </tr>
        <tr role="row" class="nhsuk-table__row">
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Case manager </span>Rita Patel
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases opened </span>1539
          </td>
          <td role="cell" class="nhsuk-table__cell">
            <span class="nhsuk-table-responsive__heading">Cases closed </span>1265
          </td>
        </tr>
      </tbody>
    </table>

  </div>

</div>
Close default tabs 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 tabs
Name Type Required Description
Name id Type string Required false Description This is used for the main component and to compose id attribute for each item.
Name idPrefix Type string Required false Description String to prefix id for each tab item if no id is specified on each item
Name items Type array Required true Description Array of tab items.
Name items[].id Type string Required true Description Specific id attribute for the tab item. If omitted, then idPrefix string is required instead.
Name items[].label Type string Required true Description The text label of a tab item.
Name items[].attributes Type object Required false Description HTML attributes (for example data attributes) to add to the tab.
Name items[].panel Type object Required true Description Content for the panel
Name items[].panel{}.text Type string Required true Description Specific id attribute for the tab item. If omitted, then idPrefix string is required instead.
Name items[].panel{}.html Type string Required true Description The title of the panel.
Name items[].panel{}.attributes Type object Required false Description The body of the panel.
Copy default tabs code
{% from 'tabs/macro.njk' import tabs %} 
{% from 'tables/macro.njk' import table %}


{% set pastDayContent %}  
  {{ table({
    responsive: true,
    panel: false,
    caption: "Past day",
    firstCellIsHeader: false,
    head: [
      {
        text: "Case manager"
      },
      {
        text: "Cases opened"
      },
      {
        text: "Cases closed"
      }
    ],
    rows: [
      [
        {
          header: "Case manager",
          text: "David Francis"
        },
        {
          header: "Cases opened",
          text: "3"
        },
        {
          header: "Cases closed",
          text: "0"
        }
      ],
      [
        {
          header: "Case manager",
          text: "Paul Farmer"
        },
        {
          header: "Cases opened",
          text: "1"
        },
        {
          header: "Cases closed",
          text: "0"
        }
      ],
      [
        {
          header: "Case manager",
          text: "Rita Patel"
        },
        {
          header: "Cases opened",
          text: "2"
        },
        {
          header: "Cases closed",
          text: "0"
        }
      ]
    ]
  }) }} 
{% endset -%} {% set pastWeekContent %}
  {{ table({
    responsive: true,
    panel: false,
    caption: "Past week",
    firstCellIsHeader: false,
    head: [
      {
        text: "Case manager"
      },
      {
        text: "Cases opened"
      },
      {
        text: "Cases closed"
      }
    ],
    rows: [
      [
        {
          header: "Case manager",
          text: "David Francis"
        },
        {
          header: "Cases opened",
          text: "24"
        },
        {
          header: "Cases closed",
          text: "18"
        }
      ],
      [
        {
          header: "Case manager",
          text: "Paul Farmer"
        },
        {
          header: "Cases opened",
          text: "16"
        },
        {
          header: "Cases closed",
          text: "20"
        }
      ],
      [
        {
          header: "Case manager",
          text: "Rita Patel"
        },
        {
          header: "Cases opened",
          text: "24"
        },
        {
          header: "Cases closed",
          text: "27"
        }
      ]
    ]
  }) }} 
{% endset -%} {% set pastMonthContent %}
  {{ table({
    responsive: true,
    panel: false,
    caption: "Past month",
    firstCellIsHeader: false,
    head: [
      {
        text: "Case manager"
      },
      {
        text: "Cases opened"
      },
      {
        text: "Cases closed"
      }
    ],
    rows: [
      [
        {
          header: "Case manager",
          text: "David Francis"
        },
        {
          header: "Cases opened",
          text: "98"
        },
        {
          header: "Cases closed",
          text: "95"
        }
      ],
      [
        {
          header: "Case manager",
          text: "Paul Farmer"
        },
        {
          header: "Cases opened",
          text: "122"
        },
        {
          header: "Cases closed",
          text: "131"
        }
      ],
      [
        {
          header: "Case manager",
          text: "Rita Patel"
        },
        {
          header: "Cases opened",
          text: "126"
        },
        {
          header: "Cases closed",
          text: "142"
        }
      ]
    ]
  }) }} 
{% endset -%} {% set pastYearContent %}
  {{ table({
    responsive: true,
    panel: false,
    caption: "Past year",
    firstCellIsHeader: false,
    head: [
      {
        text: "Case manager"
      },
      {
        text: "Cases opened"
      },
      {
        text: "Cases closed"
      }
    ],
    rows: [
      [
        {
          header: "Case manager",
          text: "David Francis"
        },
        {
          header: "Cases opened",
          text: "1380"
        },
        {
          header: "Cases closed",
          text: "1472"
        }
      ],
      [
        {
          header: "Case manager",
          text: "Paul Farmer"
        },
        {
          header: "Cases opened",
          text: "1129"
        },
        {
          header: "Cases closed",
          text: "1083"
        }
      ],
      [
        {
          header: "Case manager",
          text: "Rita Patel"
        },
        {
          header: "Cases opened",
          text: "1539"
        },
        {
          header: "Cases closed",
          text: "1265"
        }
      ]
    ]
  }) }}   
{% endset -%} 
{{ tabs({ 
  items: [ 
  { 
    label: "Past day", 
    id: "past-day", 
    panel: { 
      html: pastDayContent 
      } 
    }, 
    { 
      label: "Past week", 
      id: "past-week", 
      panel: { 
        html: pastWeekContent 
      } 
    }, 
    { 
      label: "Past month", 
      id: "past-month", 
      panel: { 
        html: pastMonthContent 
      } 
    },  
    { 
      label: "Past year", 
      id: "past-year", 
      panel: { 
        html: pastYearContent 
      } 
    } 
  ] 
}) }}
Close default tabs code

When to use tabs

Tabs can be a helpful way of letting users quickly switch between related information if:

  • your content can be usefully separated into clearly labelled sections
  • the 1st section is more relevant than the others for most users
  • users will not need to view all the sections at once

Tabs can work well for people who use a service regularly, for example, staff using a patient record system. Their need to perform tasks quickly may be greater than their need for simplicity of first-time use.

Test your content without tabs first. Consider if it's better to:

  • simplify and reduce the amount of content
  • split the content across multiple pages
  • keep the content on a single page, separated by headings
  • use a table of contents to let users navigate quickly to specific sections of content

When not to use tabs

Do not use the tabs component if the total amount of content the tabs contain will make the page slow to load. For this reason, do not use the tabs component as a form of page navigation.

Tabs hide content from users and not everyone will notice them or understand how they work.

Do not use tabs if your users might need to:

  • read through all of the content in order, for example, to understand a step-by-step process
  • compare information in different tabs, because having to memorise information and switch backwards and forwards can be difficult

Decide between using tabs, expanders and the details component

Tabs, expanders, and details all hide sections of content which a user can choose to reveal.

If you decide to use 1 of these components, consider if:

  • the user needs to view more than 1 section at a time – if not, use tabs
  • the user needs to switch quickly between sections – tabs can show content without pushing other sections down the page, unlike expanders
  • you have 7 or more sections of content – tabs are arranged horizontally, so may not work well, while expanders are arranged vertically
  • there are only 1 or 2 sections of short, less important content – the details component is more suitable as it's visually smaller and less prominent than an expander or tabs

How to use tabs

There are 2 ways to use the tabs component. You can use HTML or, if you're using Nunjucks or the NHS.UK Prototype Kit, you can use the Nunjucks macro.

The tabs component uses JavaScript. When JavaScript is not available, users will see the tabbed content on a single page, in order from 1st to last, with a table of contents that links to each of the sections.

This is also how the component currently behaves on small screens, but more research is needed on this.

Use clear labels

Tabs hide content, so the tab labels need to make it very clear what they link to. Otherwise users will not know if they need to click on them.

If you struggle to come up with clear labels, it might be because the way you've separated the content is not clear.

Order the tabs according to user needs

The 1st tab should be the most commonly needed section. Arrange the other tabs in the order that makes most sense for your users.

Do not disable tabs

Disabling elements is normally confusing for users. If there is no content for a tab, either remove the tab or, if that would be confusing for your users, explain why there is no content when the tab is selected.

Avoid tabs that wrap over more than 1 line

If you use too many tabs or they have long labels then they may wrap over more than 1 line. This makes it harder for users to see the connection between the selected tab and its content.

Research and testing

This component is experimental because we do not yet have enough research with users to be sure of it.

The Government Digital Service (GDS) developed and tested the tabs component. Several NHS services are using tabs but we need to know more about how they test with users.

For example, we need to know:

  • which types of services tabs work best in
  • that this approach to tabs is the best option for screen reader users and sighted keyboard users
  • how this component should behave on small screen sizes

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: April 2023