Category group
The section that opens with a head and holds what belongs under it: four subscriptions under "Streaming (4)", two alerts under "Needs you", three switches under "What Tendd tells you about". It is what turns fourteen rows into five readable groups, and it is the reason Home has no heavy heading anywhere.
Anatomy
A head, a list, and a hairline between two items. That is the whole component. Everything below is drawn by design/system/components/category-group.css and by the files of the components inside it, through the same entry point a product screen loads, so this page cannot drift from the screens: there is no second copy of the CSS here to drift from.
Streaming (4)
$54.96 a month-
Netflixin 2 days · Aug 3 $17.99 Price changed
-
Disney+in 11 days · Aug 12 $13.99
-
Huluin 24 days · Aug 25 $7.99
Behaviour at width
From --bp-desktop, 56.25rem: break-inside: avoid. One declaration, and outside a multicolumn container it does nothing at all, which is why it is written here rather than on the column set: the subject of the rule is the group, and the subject owns it.
What it prevents is a rendering fault on the screen whose job is calm: without it a category's four subscriptions split across the fold and the group heading is left alone at the bottom of column one. See Width.
.groupthe organism itself, and it is asectionon all 32 occurrences. Its only declaration of its own ismargin: 0 0 24px: no fill, no edge, no radius and no padding.group-heada molecule. The Group head, with its own 12px uppercase type, its own hairline under it and its own figure at the far end. This file gives it no rule at allulthe list, with the browser's bullets and its 40px indent taken off. Selected by tag and not by class, because the product writes it three ways: bare on Home, and as a.divliston Alerts and on Settings, which were.alertsand.navrowsuntil step 6li + lithe one line this component draws. Aborder-topin--line-divider, between two items and never around them. There is no line after the last item, so nothing has to reach back into the item to take one off.rowa molecule. The Subscription row, which writesborder: 0in its own file precisely so that this hairline is the only onebreak-insidepast a 900px container the group refuses to be split by a column break, because a head at the foot of one column with its rows at the head of the next is the one thing a grouped list may not do
No fill, no edge, no corner, and that is the decision the component is. Five groups stack on Home with only their heads and their hairlines to tell them apart. Five bordered boxes down a phone screen is the compartmented look the visual language was chosen against, and DESIGN.md says so in one line: rows stack inside one bordered container so a list reads as one object rather than as a stack of cards. Where a group does want paper and a corner, the container around it is the Panel and the group is still this.
Variants and sizes
One form, so there is no matrix. A margin, a list reset and a hairline, and they are the same on all 32 occurrences across the 12 pages. There is no dense group and no bordered group, and a group never changes size: what changes between one group and the next is what is inside it, and everything inside it is a component with a page of its own.
The name is narrower than the job, and the count is where you see it. Five of the twelve pages group subscriptions by category, which is the screen the component was named on. The other seven group alerts by urgency (alerts, 2 groups), settings by subject (settings, 3), promises by topic (data-privacy, 3). The class is .group on all twelve and the component is one component: a titled section with an optional divided list inside it. The name comes from where it was found, which is how docs/inventory.md names everything, and step 9 may widen it.
| What it holds | Pages | And what draws the hairline |
|---|---|---|
Subscription rows, in a bare ul | 5 | this file, and only this file: the list has no class to hook |
Alert items, in ul.divlist | 3 | this file and Divided list, with the same declaration and the same token, so nothing renders twice |
| Form fields and switch rows, no list at all | 4 | nothing. The rule matches no element, and the group is a margin and a head |
The overlap in the middle row is deliberate and it is recorded. docs/inventory.md settled it at step 2 in one line: there were three identical li + li divider rules in kit.css, two of them merged into .divlist, and "the third belongs to .group and stays a usage". It stays because the bare list on Home has nothing else to draw it, and it is harmless where the two meet because both read --line-divider at 1px.
One responsive rule, and it is not a variant. Past a 900px container the group takes break-inside: avoid, because the Groups column set around it runs in columns from there, as many 300px columns as its container holds and never more than three. The column count belongs to that wrapper; what belongs here is the group's own refusal to be cut in half. kit.css also re-declared the margin in that block at 26px, and that half is deleted: 26 lands on --space-24 under the founder's grid, which is what the base rule already sets, so the override became byte-identical to the rule it was overriding. Measured either side of the step: 24px at an 892px container and 24px at 908px. It goes for the same reason .btn.compact went, which is that a declaration changing nothing costs the next reader a minute.
When to use it
A group is for a set of things that share a reason, with a head that names the reason. J-MAIN reads "I want to see all my recurring charges in one calm view", and the calm comes from the grouping: fourteen rows in one undifferentiated column is a list a person has to read, and five groups of two to four is a list a person can scan. The head carries the count and the subtotal so the group answers its own question before any row is read.
On the path a person meets it first on Home, which is the screen the product exists for, and then everywhere a screen has more than one subject: Alerts splits into "Needs you" and "Just so you know", Settings into "Your details", "Your plan" and "What Tendd tells you about", Data and privacy into three plain answers. Every head comes from voice/docs/microcopy.md and every one of them is a phrase rather than a category word: "What Tendd tells you about", not "Notifications".
The subtotal is a fact and never a verdict. "$54.96 a month" sits at the far end of the head in the muted tier at the same size as the heading, because it is context for the group and not a second heading. It never carries a colour, an arrow or a comparison: the one number allowed to be loud in this product is the monthly total, and a group subtotal competing with it would break the One Number Rule five times on one screen.
The rule, and the anti-rule
Music (2)
$14.98 a monthOne hairline, between the two rows, and none under the second. The row itself draws border: 0, which is why the last row needs no rule to undo one. Hover either row: the fill changes and the line does not move, because a border appearing under the pointer would shift every row below it by a pixel.
The row is written and it is correct: the census measured 47 of them across six coloured pages and found one value on every one of twelve properties, which no other component in the sweep managed. A rule here that changed a name's size would end that, and it would end it invisibly, because the group and the row are never on screen apart. Measured on this page: the merchant name inside the group is 16px at weight 600, which is exactly what it is on its own page.
Your plan
FreeUnlimited subscriptions and unlimited bank connections. History, trends and advanced alerts are part of Tendd Pro.
A section of a screen that has more than one subject, named by its head. It holds no list at all here, and that is a third of its occurrences: the divider rule simply matches nothing, and what is left is a margin and a head, which is exactly what this block needs.
When the section is one thing a person acts on rather than a set of things they scan, the container is the Card: paper, a hairline all the way round and a 14px corner. A source on Your sources is a card because each connection is a separate decision; "Streaming (4)" is a group because the four rows under it are four decisions and the head is only telling you what they have in common. The test is the head: a group's head describes what is below it, a card's title is the subject.
States
None, and the reason is one line: a group is not interactive. It is a <section> on all 32 occurrences, it holds no anchor, no button and no summary of its own, it carries no tabindex and no role, and it does not collapse: the one disclosure in the app shell is a details.panel summary and that is the Panel. kit.css gave it no hover, no active and no focus rule, and adding one would be inventing behaviour the product does not have.
Everything inside a group that answers a pointer answers it as itself, and each is live on its own page: the Subscription row has hover and focus-visible, the Alert item has hover and focus-visible, the Nav row has both as well. The specimens above are real anchors with real hrefs, so hover one and the hover you see is the row's own, read off the real thing rather than off a photograph of it.
The technical half
| Reads | Which token | Growing from |
|---|---|---|
| the line between two items | --line-divider | --hairline-soft, and --hairline-soft-dark in the dark theme. Decorative, so it owes no threshold: 1.23:1 light is what keeps a list of fourteen from reading as a table |
| the space under the block | --space-24 | primitive, straight |
| the list reset | --space-0 | primitive, straight. Zero is a real value here and not the absence of one |
| no fill, no edge, no radius, no padding | none | by decision. The group is a grouping, not a container |
| no colour and no type of any kind | none | the head owns its type, the rows own theirs. This file reads two tokens in total |
It hosts three molecules and paints none of them. Group head, Subscription row and Alert item get no rule here at all, not even a margin: the head spaces itself, the rows are separated by the one hairline above, and the whole file is four declarations long. It is the shortest organism in the system and that is the point of it.
The container query is measured on both sides, because a query that never fires looks calm. break-inside: avoid arrives at a 900px container. It needs an ancestor with container-type: inline-size, which base.css declares once on body; nothing in this file declares a second one, because a container between the body and these rules would re-point the query at a different box with no error and no symptom.
Lives in design/system/components/category-group.css. Stands on 13 grey pages and 13 coloured ones, 36 groups on each side. Coloured screens carrying it: Home, Home, could not refresh, Home, save focus, Home, loading, History and trends, Settings, Settings, no account, Alerts and its empty and loading states.
<section class="group" aria-label="Streaming">
<div class="group-head">
<h2>Streaming (4)</h2>
<span class="subtotal">$54.96 a month</span>
</div>
<ul>
<li><a class="row" href="subscription-detail.html" aria-label="...">...</a></li>
<li><a class="row" href="subscription-detail.html" aria-label="...">...</a></li>
</ul>
</section>
The specimens above stand in .kit-stage app full wide, 620px, because that is a width the product gives them: measured at a 1440 viewport, a group renders 620px on Settings and 424.5px on Home, where two column groups share the screen. The stand's default 440px would be right for Home alone and would crush the Settings form.