Group head

The small uppercase line that opens a section, with an optional figure at the far end. It is the second most repeated structure in the product after the subscription row, and it is what lets a screen carry twenty sections without a single heavy heading anywhere.

Molecule16 grey pages1 axis, 2 valuesno statesbound to the class, not the tag

Anatomy

Two content slots, a heading and an optional figure, which is what makes it a molecule. Everything below is drawn by design/system/components/group-head.css through the same entry point a product screen loads, so this page cannot drift from the screens.

Streaming (4)

$54.96 a month

It hosts no atom, and the figure is deliberately not one. .subtotal looks like a place for the Amount and is not: it never takes the amount's weight or its primary ink, because here the money is a fact about the group rather than the subject of the line. Two things that would be the same object at the same value are still two objects when their jobs differ, which is the naming rule in docs/architecture.md applied one level up from tokens.

Variants and sizes

Two axes, and the second one arrived on 2026-08-20. The first is about what stands UNDERNEATH: banded is the default and draws a rule, plain takes the rule off, and the choice is made by the thing below the head rather than by the importance of the section. The second is about what stands in the FAR SLOT: a figure, which is all it had ever held, or the section's own action. Nothing in the definition of this molecule ever said the far slot was a number; the subtotal was simply the only thing that had stood there.

Rule

Banded when what follows is a bare list or a set of fields, which have no edges of their own and need the head to close off the section above. Plain when what follows already draws its own edges, a grid of tiles or a row of chips: a hairline above a bordered grid is two lines saying one thing

Measured Where it stands
Banded .group-head 8px padding
2px margin
1px --line-divider
34 of the 46 coloured occurrences, and every one of them a div wrapping a heading. Category groups on Home, the field groups and the plan line on Settings

Streaming (4)

$54.96 a month
Plain .group-head.plain 0 padding
16px margin
no border
9 coloured occurrences, and every one of them is written directly on a heading: h2 on Add a Subscription and its loading state, h3 on the guided reveal. Which is exactly the pair of screens that broke it

Most tracked

Carrying the section's action .group-head:has(> .actions) centred
wraps at 320
24px margin
3 coloured occurrences and 3 grey: the head of the list on Home and on its error and Save-focus states. Founder's decision, 2026-08-20, on a desktop row that held one outline button and 1370px of nothing beside it

Your subscriptions

Content

The figure appears when the group has one number that describes it. It is not "a total for every section": a section of fields or switches has nothing to sum, and an empty far end is correct there

Measured Where it stands
With a figure 12px, tabular, nowrap Home's category groups, and Settings, where the far end holds a plan name rather than a sum

Software (4)

$53.98 a month
Without - Settings' field groups. The heading takes the whole width and the row is still a flex row, so adding a figure later moves nothing else

Your details

Loading 104px and 90px The loading states. The host owns the slot widths and the skeleton bar draws the bars. Two different widths on purpose: a column of identical bars reads as a progress meter, and a loading state is not progress

There is no size axis and there must not be one. The head is 12px on every screen at every width, and that is what makes a group head recognisable as a group head from across a long page. A larger one is a page subject, which is the text block, and a smaller one is an eyebrow.

When to use it

A group head opens a section of like things: four streaming subscriptions, three preset tiles, the fields that make up your details. It is the quietest possible way to say "a new kind of thing starts here", and quiet is the requirement rather than a preference: Home carries five of them in a column and a person is meant to scan past four of them to find the one they came for.

Uppercase at 12px with tracking does the work a heavier weight would otherwise do. It is small caps behaviour without a second typeface, which matters because DESIGN.md forbids a display face by name: one family for the whole product, and a second family is how a calm interface starts sounding like two products.

The figure at the far end is context, in the plain money language sense: "Streaming (4)" and "$54.96 a month" together say what the group is and what it costs, and neither is useful alone. On Settings the same slot holds the word "Free", which is the same job with no arithmetic in it. Since 2026-08-20 it also holds a control, on the head of Home's list: "Your subscriptions" against "Add a subscription". That is the same sentence shape one step further - what the group is, and the one thing you can do to it - and it is why this needed no new component. What the slot may never hold is a SECOND heading: two headings on one line is a row with no subject.

The rule, and the anti-rule

Any heading level, one look

Most tracked

Streaming (4)

An h2 and an h3, identical on screen. The document picks the level from the outline it needs, the component picks the look from the class, and the two never have to agree. This is what :where(h1,h2,h3,h4).group-head buys, and it costs no specificity at all.

Never bind the look to a tag

Streaming (4)

That is what this component used to be, and the picture above is what it looked like when it broke: a browser-default heading, 24px and black, next to 12px uppercase muted everywhere else. It broke twice for the same reason, once on the form screen where the h2 IS the head, and again on the guided reveal where the head is an h3 inside a group, and both times on a screen that had already been accepted. A component whose typography depends on which heading level the document happened to need is not a component.

Use a group head to open a section

Music (2)

$22.98 a month

A label on a set of like things, with the one number that describes the set. It repeats down a screen without ever competing with the content it introduces.

Use a text block for the page's subject

We could not load your subscriptions

Nothing is lost. Try again in a moment.

When the heading is what the screen is about rather than a divider inside it, the component is the text block, written .textblock or .textblock.status. The tell: a group head is followed by items, a text block is followed by an action. Setting a page subject in 12px uppercase muted would leave a screen with no subject at all, which is exactly what a person arriving on an error state cannot afford.

States

None, and it was checked rather than assumed. A group head is a label on a section: it holds no anchor, no button and no disclosure on any of the 57 grey pages or the 57 coloured ones, 36 heads on one side and 41 on the other, and the sections it opens are not collapsible in this product. The one disclosure the app shell does have is a details.panel summary on the alerts screen, which is the panel organism and a different component with its own indicator. The loading form in the matrix above is content, not state: it is what the block holds while the figures arrive, and it belongs to the skeleton bar.

The technical half

ReadsWhich tokenGrowing from
the heading and the figure--text-muted--muted, 5.8:1 light and 6.4:1 dark. One tier for both, because they are one line
the rule underneath--line-divider--hairline-soft, decorative: 1.23:1 light is deliberate
the type step--type-metaprimitive, straight: a size has nothing to override
gap, padding, margins--space-16, --space-8, --space-2, --space-0primitive, straight
the two skeleton slots104px and 90px, literalslot widths, which are not on the spacing scale. The host owns the slot, skeleton-bar.css owns the bar, and that file names these two rules as belonging here

Three values moved and none was re-decided. The gap was 12px and is 16, the padding under the heading was 6px and is 8, the plain form's bottom margin was 12px and is 16. Nearest step, ties to the larger, straight from the founder's review of the foundations. Everything else measured identical before and after on the real Home screen: 12px, weight 600, 0.72em-equivalent tracking, the muted ink, the 2px bottom margin and the divider colour.

One rule of this component lives in another file, and it is named in both. .app .rgroup .group-head { margin: 0 0 8px } belongs to the merchant chip group, because it is that molecule positioning this one. It ties with .group-head.plain at 0-3-0 and is decided by source order, which the @import order settles by itself: alphabetically inside the molecule level, group-head.css comes before merchant-chip-group.css, so the host wins. Measured on this system: 8px, as the product renders today.

Lives in design/system/components/group-head.css. Stands on 17 grey pages in 43 places and on 18 coloured ones in 48, recounted 2026-08-20 by design/kit/screens/counts.cjs, which reads the places as well as the pages since that day. The colour is more than the grey: the five places past it are on screens the grey writes without a head. A sample of the coloured screens carrying it: Home and three of its states, Add a Subscription and its loading state, Guided Reveal, History and Trends and its loading state, Settings, Settings with no account, Alerts and its empty and loading states.

<div class="group-head"> <h2>Streaming (4)</h2> <span class="subtotal">$54.96 a month</span> </div> <h2 class="group-head plain">Most tracked</h2> <div class="group-head"> <span class="skel"></span><span class="skel"></span> </div>