Divided list
A stack of whole molecules with a hairline between them and no line top or bottom: eight alerts on the Alerts screen, four destinations on Settings. It is the container that lets a row draw no edge of its own, which is what makes a list read as one object rather than as a stack of cards.
Anatomy
A list reset and a hairline between two items. That is the whole component, and everything a person actually looks at inside it belongs to the item. Everything below is drawn by design/system/components/divided-list.css and by the files of the items 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.
.divlistthe organism itself, and it is aulon all 7 occurrences. Bullets and the browser's 40px indent off, no fill, no edge, no radius. It was.alertsand.navrowsuntil 2026-08-12, and both already took one rule, which is what made the merge a rename rather than a decisionli + 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.navrowa molecule. The Nav row, with its own 56px floor, its own drawn chevron, its own inherited ink and its own hover and focus ring. This file gives it no rule at all.alerta molecule. The Alert item, the other thing this list holds. Also untouched by this filemargin--space-24under the list, and it is the host's rather than the component's: the nav list is the last block on Settings and has a tab bar under it. Written.rows-col > .divlist, keyed to the column it stands in, because one name cannot carry two margins and the other list never had one. The rule moved toapp-shell.csson 2026-08-20, on the founder's decision: same selector, same value, one file to the left
No edge and no corner, and that is what makes the item able to have none either. Four nav rows and eight alerts stack with three hairlines and seven, and not one of them is drawn by the item. nav-row.css and alert-item.css both write no border at all, exactly as subscription-row.css does, and the reason is the same in all three: an item that drew its own floor would draw a second one everywhere a list did its job.
Variants and sizes
One axis, two values, and the rule for choosing is the container. The axis is not emphasis and not density: it is whether the list stands on the page or inside a panel, and the answer is read off the markup rather than decided by anyone.
| Inset Set by the CONTAINER and never by importance. A list inside a |
What changes | Where it stands |
|---|---|---|
Bare .divlist |
--space-0 on all four sides |
6 of the 7 lists. The items reach the full column, and the head above them belongs to the Category group rather than to a container |
Inside a panel .divlist.inset |
padding 0 --space-16 --space-8 |
1 list in the product, the "Older" disclosure on alerts.html, and it is the only .panel that holds a divided list. The rule also still answers to .panel .divlist, and that second subject is transitional: see the note under this table |
| Bordered, or striped | - | Forbidden with a reason rather than missing. An edge around the list is the Panel's and a fill on one item is the Charge list's .marked, which is a domain state and not a stripe. Alternating fills would rank the items, and ranking is the work this product takes away from the person |
The inset has a declared name and no markup wearing it yet, and that is reported rather than worked around. The rename sweep matches on a tag and a class list and cannot see a parent, so it could not tell a list inside a .panel from a list on the page, and no page writes class="divlist inset" today. Three specimens needed the token when this was written, all of them in the stand and none on a product screen, because at the time no coloured screen held a panelled list: divided-list.html line 95, and panel.html lines 107 and 164. One product screen holds one now: Alerts puts its "Older" list inside a details.panel, coloured on 2026-08-13, so the second subject on this rule has a real wearer and is no longer a stand-only branch. Until the token lands, divided-list.css carries .panel .divlist as that second subject, so nothing renders wrong for a day. Measured in a browser at 360 and at 1280, all three compute padding: 0px 16px 8px, which is what .panel .alerts computed before the rename once the spacing grid had moved 14 to 16 and 6 to 8.
One difference between the two old names has no row in the renaming map, and it is the margin. .navrows carried margin: 0 0 22px and .alerts carried none, because the nav list is the last block on Settings with a tab bar under it while the alert list sits inside a Category group that already spaces itself. One name cannot carry two margins. It is written .rows-col > .divlist, keyed to the shell's content column, which is the same shape as the inset above and follows the convention app-shell.css states in its own words: a container-keyed rule about this list lives in this list's file. THE FOUNDER CHOSE THE SHELL ON 2026-08-20 and the rule left this file. Two shapes were on the table and both cost an edit outside this component: a declared .divlist.spaced modifier, which needs a class on two product screens and COLLIDES with muted-line.css's .spaced, where the same word means a margin above; or a rule in app-shell.css, which is what action-row.css did with its own 24px in this same round. The shell won on the collision: one word meaning two things in one system is worse than a gap declared one layer out, and there was a precedent to follow rather than a shape to invent. Measured after the rename: 24px under the list on both Settings screens at 360 and at 1280, and 0 on every other list in the product and the stand.
The charge list is deliberately the other answer to the same question, and the pair is worth reading together. It also sits inside a panel and it does not indent: it is a full-bleed band, because a marked row's amber wash has to reach the panel's own edges or the wash reads as a highlighted rectangle floating inside a card. Two lists, one host, two answers, and the difference is whether an item can be filled.
No size axis. The list has no type, no padding on its items and no height of its own; a nav row is 56px because nav-row.css says so and an alert is as tall as its own three lines. What changes between a list of four and a list of eight is the number of items.
When to use it
A divided list is for a set of whole objects a person moves through one at a time: four destinations on Settings, eight events on Alerts. Every item is a link, every item is one target with one accessible name, and the hairline between them is the only thing the container contributes. If the items are not each a whole thing a person can go to, this is the wrong container.
On the path, a person meets it in the two places where the product stops being a list of money and becomes a list of choices. Settings, node 6.16, is four nav rows whose second lines come from voice/docs/microcopy.md and answer "what is behind this" in the person's own words: "Data and privacy" carries "What we read, and delete everything", not a category name. Alerts, node 3.8, is eight alert items split into two groups by urgency, and the inset form holds the older ones behind a disclosure so the screen opens on what needs the person now.
Trust through transparency is what the second line is for, and it is why this list never collapses to a single word per row. "Your sources" alone is a destination; "Your sources / Banks and manual entries you track" is a promise about what a person will find there, and on a screen whose job is to make an avoider willing to look, that second line is the component's whole reason to be two tiers rather than one.
The rule, and the anti-rule
One hairline, between the two rows, and none above the first or below the second. Hover either row and the fill changes while the line stays exactly where it was: nav-row.css declares its hover as a fill and nothing else for this reason, because a border appearing under the pointer inside a stack of four shifts the three below it by a pixel.
The item is written and it is correct: the census measured all 8 nav rows at one value on every property. A rule here that changed a destination's size or weight would be an undeclared variant, and it would be invisible, because the list and the row are never on screen apart. Measured on this page: the destination inside the list is 14px at weight 400 with a 56px floor, which is exactly what it is on its own page.
Two whole molecules, each a link, separated by one line. The list is holding events that happened on dates, and each one goes somewhere.
- Last checked
- today, 9:14 AM
- Accounts included
- Checking
When each line is a label and a value rather than a whole object, the component is the Pair list. The two look alike from a distance and answer different questions: a divided list is a set of destinations, a pair list is the facts about one thing. Read the difference in the markup and not in the CSS. A divided list's item is an anchor with an accessible name; a pair list's line is a dt and a dd and goes nowhere. Building facts out of nav row markup would give a person four targets that lead nowhere.
States
None, and the reason is one line: a list is not interactive. It is a <ul> on all 7 occurrences, it holds no anchor, no button and no summary of its own, it carries no tabindex and no role, and neither kit.css before the rename nor divided-list.css after it gave it a hover, an active or a focus rule. There is nothing here for a pointer to be over: a pointer that looks as though it is over the list is over an item or over the gap between two.
Every target inside it has its states on its own page, and both were written so that neither moves its neighbours: the Nav row has hover and focus-visible, the Alert item has hover and focus-visible, and both change a fill or paint a ring outside the box. That promise is what a stack of eight depends on, and it is why the divider stays put while a row lights up. The specimens above are real anchors with real hrefs, so hover one and tab to it, and read the value 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: eight alerts separated at 1.23:1 read as one object, and the same eight at 3:1 read as a table. Between two items and never after the last, which is li + li rather than a :last-child reset |
| the list reset | --space-0 | primitive, straight. Zero is a real value here and not the absence of one |
| the space under the nav list | --space-24 | primitive, straight. 22px before the fold, measured at 24px after it on both Settings screens at both viewports. Keyed to .rows-col, the shell's content column, and declared in app-shell.css since 2026-08-20. It is the one difference between the two old names that the renaming map has no row for |
| the inset, inside a panel | --space-16, --space-8 | primitive, straight. 16 to line up with the panel's own head, 8 to lift the last item off the panel's bottom edge |
| no fill, no edge, no radius, no type | none | by decision. The items own everything a person reads |
It hosts two molecules and paints neither. Nav row and Alert item get no rule here at all, not even a margin. The whole file is four declarations long, and the third of them is the inset variant, which moves the list's own padding and touches nothing inside it.
No container query and no media query touches it. Checked. The list is the same object at 360 and at 1440; what changes with the width is the column it stands in, and that belongs to the shell. What it does have is the third copy of its divider rule living elsewhere: the Category group declares the same li + li border for the bare <ul> on Home, which has no class to hook. docs/inventory.md recorded that at step 2 and it is a usage rather than a duplicate.
The last-row principle was already this component's shape, and on 2026-08-12 it became the system's. The founder's review of the components ruled that the last row of a divided list draws no bottom rule, because a divider divides two things and after the last row there is nothing to divide. Nothing changed here, and the rename did not change it either. li + li has never drawn a line after the last item, which is the same principle written the other way round, and it is why the seam docs/backlog.md recorded was never this list's. Re-measured after the rename, on every list in the product and the stand at 360 and at 1280: the first item computes border-top: 0px, every later item 1px, and every item without exception border-bottom: 0px.
The seam held and it is closed. Measured on design/subscription-detail.html at 360 and at 1280: the last charge row computed border-bottom: 1px rgb(238, 242, 243), the gate below it computes border-top: 1px rgb(238, 242, 243), and the two rectangles touched at exactly 0.00px. That one seam carried 2px of --line-divider where every other divider in the panel carries 1. It survived unnoticed because the gate's own fill is --bg-recessed, which is a near neighbour of the divider colour, so the doubled line read as a slightly heavier edge rather than as an obvious defect.
The rule that moved is the charge list's, not the gate's. charge-list.css now resets the bottom border on li:last-child; the Panel's .gate:not(:first-child) keeps its top rule unchanged. That direction was chosen because the other one closes only this seam: on the loading state there is no gate, the charge list is the panel's last child, and its final rule sat flush at 0.00px against the panel's own hairline. A principle closes both, a patch closes one.
Lives in design/system/components/divided-list.css. Stands on 4 grey pages, 7 lists: alerts (3), alerts-loading (2), settings (1), settings-no-account (1). All four are coloured as of 2026-08-13: Settings, Settings, no account, Alerts and its loading state. The alert lists were the half that had never been drawn in colour, which docs/census.md listed among the nine components with no occurrence in the sample; the specimens on this page were their first rendering in Petrol and Paper, and the product caught up with them at stage 09 step 5.
<ul class="divlist">
<li><a class="navrow" href="connections.html"><span>Your sources<span class="sub">Banks and manual entries you track</span></span><span class="arrow">›</span></a></li>
</ul>
<ul class="divlist">
<li><a class="alert" href="subscription-detail-price-change.html" aria-label="...">...</a></li>
</ul>
<details class="panel"><summary>Older</summary>
<ul class="divlist inset">...</ul>
</details>
The specimens above stand in .kit-stage app full wide, 620px, because that is what the product gives them: measured at a 1440 viewport, the nav list renders 620px on Settings and an alert list 620px on Alerts. The stand's default 440px is the row column on Home and would show both narrower than either screen ever does.