---
title: Tabs
slug: tabs
kind: pattern
summary: One record or screen split into a few named sections, only one visible at a time, with the section in the URL so a tab can be linked to.
problem: >-
  A record page grows past a screenful, so everything is stacked vertically and
  the person scrolls past four sections they do not care about to reach the one
  they do — every single time.
family: [orient, inspect]
data_shape: [record]
principles: [progressive-disclosure, orientation]
interaction: [navigation, disclosure]
density: low
complexity: low
status: stable
visibility: public
use_when:
  - The content splits into a few named sections people think of as separate.
  - Different people, or the same person at different times, want different sections.
  - Each section is substantial enough to be worth a screen.
avoid_when:
  - People need to compare across sections. Tabs make that impossible by design.
  - There are more than about six sections, where the tab bar becomes navigation.
  - One tab is opened 95% of the time — that content should just be the page.
  - The sections are short. Stacking them costs one scroll and no clicks.
alternatives:
  - slug: collapsible-section
    when: People need several sections at once, or the sections are short.
  - slug: persistent-navigation
    when: The sections are really separate screens with their own workflows.
ask_leo: |
  Split this record page into tabs.

  - Use between two and six tabs, named as nouns a person would say — Details,
    Line items, History, Files. Not verbs, and not internal model names.
  - The first tab is what most people came for, and it is the default.
  - Put the active tab in the URL so a tab can be bookmarked, shared and
    restored after a reload or after leaving and coming back.
  - Mark the active tab with weight and a rule, not colour alone.
  - Show a count on a tab when the count is decision-relevant — "Files (0)"
    saves a click, and "Comments (3)" earns one.
  - Keep the record's identity header ABOVE the tab bar, so it stays visible on
    every tab. The tabs switch the detail, never the identity.
  - Do not hide anything urgent behind a non-default tab. If a person must act
    on it, it belongs on the first screen or in the header.
related:
  - title: Progressive Disclosure for Dense Detail Pages
    url: /cookbook/progressive-disclosure-detail-page
    summary: The implementation guide, including when tabs beat collapsing.
  - title: Object Identity Header
    url: /patterns/object-identity-header
    summary: What stays above the tab bar, on every tab.
---

## Anatomy

```
INVOICE #1043 · Riverside Fit-Out · Overdue 12d      ← header: always visible
──────────────────────────────────────────────────
 Details │ Line items (7) │ History │ Files (0)
 ═══════
   ↑ active: weight + rule, and in the URL as ?tab=details
```

- **The identity header sits above the tabs.** If switching tabs changes who you
  are looking at, they were not tabs, they were navigation.
- **The active tab is in the URL.** Without it, every link to the record lands on
  the default tab and every reload loses the person's place.
- **Counts where they decide something.** "(0)" is as useful as "(7)" — it saves
  the click.

## Why it works

Tabs are progressive disclosure with an unusually good door: the door is
labelled, permanently visible, and shows how many other doors exist. Compared
with collapsed sections, tabs make the *whole shape* of the record visible from
any one view.

They also let one page serve people with different jobs. A salesperson wants
Details, finance wants Line items, support wants History. Stacked vertically,
each of them scrolls past the other two.

## The trade

Tabs make **comparison across sections impossible**. You cannot see line items
and history at once, by construction. That is the entire cost, and it is why
tabs are wrong whenever the job requires holding two sections in view — there,
[collapsible sections](/patterns/collapsible-section) or a two-column layout are
correct.

The second cost is hiding. Anything behind a non-default tab is invisible to
someone who does not go looking, so a tab is the wrong home for anything urgent.
The count on the tab is the mitigation, and it only works for things that can be
counted.

## Getting it wrong

- **Tabs as navigation.** Six tabs where each is a different object with its own
  workflow — that is a nav bar with the wrong styling.
- **No URL state**, so tabs cannot be linked and reload resets them.
- **Something urgent on tab four.** Nobody sees it, and the record looks fine.
- **A tab bar that scrolls sideways**, which hides the existence of tabs — the
  one thing the pattern is supposed to make visible.
- **The identity header inside the tab**, so it disappears when you switch and
  you lose track of what you are looking at.

## Exemplars

**Stripe's customer page** keeps the identity and balance fixed and tabs the
detail beneath — payments, subscriptions, invoices — which is the correct
division: one subject, several bodies of detail.

**GitHub repository tabs** (Code, Issues, Pull requests, Actions) sit right at
the boundary between tabs and navigation, and their URL-per-tab is what makes
them work at all: every tab is a linkable destination.

The extractable rule: **tabs divide the detail, never the subject.** If
switching a tab changes what the page is about, you needed navigation instead.
