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 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.