Nav row

The line that takes a person somewhere else: a destination, a sentence saying what is behind it, and a chevron. It is the whole of the Settings screen's navigation and the one place in this product where a person browses rather than acts.

Molecule2 grey pagesone form3 states, both themeshosts no atom

Anatomy

One anchor, three slots and one of them unnamed. Everything below is drawn by design/system/components/nav-row.css 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.

It hosts no atom, which makes it the plainest molecule in this group: two text slots and a mark, and every one of them is its own. It is a molecule rather than an atom because it holds more than one content slot in one unit, which is the line the component ladder draws.

Variants and sizes

One modifier since 2026-08-20, and it is the absence of a mark. .navrow.leave is the one row in the product that leaves instead of going deeper - "Sign out" on Settings - and what it drops is the chevron. A chevron means "there is more this way": it opens a disclosure twice on that same screen and points into every other row of the list, so drawing it on the control that ends the session says the opposite of what the control does. Same argument the app bar's back control made on 2026-08-17, when its chevron became an arrow. Nothing else changes: same 56px row, same ink, same hover, same divider. A row that leaves is not a warning and takes no red, no weight and no edge of its own. The mark left the MARKUP rather than being hidden by CSS, because a mark nobody should see is markup nobody should write.

Otherwise the nav row has one form. All eight instances in the product render identically, and the census measured .navrow as one of the sixteen families with a single value on every property, at both viewports. The third specimen above shows the one thing that varies, and it is content and not a variant: .sub is an optional slot, present on three of the four rows and absent on "Sign out", because there is nothing to say about signing out that the words do not already say.

Size is not an axis either. The row's floor is --row and the two text tiers are --type-body and --type-meta on every page, so a nav row on Settings is the same object as a nav row on the account-less variant of it.

What is NOT here Why the cell is empty Verdict
A destructive or session-ending modifier "Sign out" wears exactly the same class as three navigation rows, with no modifier saying it is not navigation. docs/census.md lists it as case 9 of the twelve controls with no family. Naming a modifier here would either change how Settings renders, which this stage may not do, or add a class the product does not carry a line in the backlog
step 9 decides
A current or selected state Forbidden with a reason rather than missing. A nav row never marks where a person is. Marking the current destination is the tab bar's job, it is drawn in petrol and a left border on the desktop rail, and a second component claiming the same signal would give one screen two answers to "where am I". A nav row is always a way out of the screen it stands on prohibited
An icon in front of the label Forbidden with a reason. The four destination masks in destination-icon.css are the tab bar's whole set, and a row of four leading icons on Settings would make four ordinary lines look like four decisions. The chevron at the end is the whole affordance the row needs prohibited

When to use it

A nav row is for a destination that has somewhere to go and something to explain. All eight in the product sit on the two Settings screens and lead to the places a person visits rarely and needs to trust completely: "Your sources", "Data and privacy", "Help and support", and the door out of the account. Each carries a plain sentence underneath, because a person who is one tap from deleting everything they hold should know what is behind the tap before they take it.

The second line is where the voice does its work. "Data and privacy" is followed by "What we read, and delete everything", not by "Privacy settings": the sentence states the promise and the escape hatch in six words, which is principle 4 read at the smallest scale the product has. On the account-less variant of Settings the same row says "3 subscriptions you typed, and nothing connected", so the row describes what is actually true for that person rather than what the screen is called.

It is a way out of a screen and never a way around inside one. The product has exactly four destinations and they live in the tab bar; a nav row is what a destination offers once a person is already there. If a screen grows a list of nav rows that lead back into itself, the screen is a hub and wants a different structure.

The rule, and the anti-rule

A destination, with what is behind it

Tapping it changes the screen and nothing else. Nothing is saved, nothing is sent, nothing is undone. The chevron says so, and it points the way a page turns.

Use a button instead

An action that commits, sends, ends a session or cannot be undone belongs to the Button. A chevron is a promise that the next screen is a place, and a row that quietly signs a person out or deletes something has broken that promise. This is a live open row rather than a hypothetical: "Sign out" is a nav row on Settings today, and the census flagged it as a control with no family. It is carried, not fixed here, because fixing it would change how the product renders.

Somewhere to go

The answer lives on another screen, so the row leads there. Four of these stack in a divided list and read as a short table of contents for everything a person owns.

Use a switch row instead

A preference that is on or off and takes effect where it stands is the Switch row. The two look alike on Settings and they are opposites: one leaves the screen, one changes something without leaving it. A person who taps a nav row expecting to arrive somewhere and instead flips a setting has lost the thread of what they just did, and on a screen about their bank data that is expensive.

Limits

U13, context. ADVANCE and PRESS. The chevron points right and the row goes to another screen, so it advances right by one nudge on hover; the row itself goes down by one on :active. Everything in this product that moves travels exactly one --nudge, which is 2px, and nothing anywhere travels two. Hover and release run at --dur-state (150ms) on --ease-arrive; a press runs at --dur-press (90ms), because it answers a finger that is already down. The full language and the live specimens are on Motion; the table with sources is Usage rules.

States

Three states, and they exist because the row is a link. Each is a token override rather than a style of its own, so the dark theme costs nothing in this file.

Three rather than four. There is no disabled nav row: a destination a person may not reach is not rendered dim, it is not rendered. Settings without an account carries four rows and not five greyed ones, and its fourth says "Sign in" where the account version says "Sign out". And there is no :active, because kit.css declared none and writing one here would be a new decision about how the product answers a press.

Rest, live

Real anchors with a real href, which is the only way the states below can be reached at all. The divider a person sees between two of these on Settings is not here: it belongs to the Divided list organism, which draws it in the product.

The three, in both themes

The states are described, not photographed. Founder's decision, 2026-08-11: the snapshot strip went from every page in this kit, 120 images across 18 pages. They were framed as measurements rather than illustrations, and that framing was honest, but the bill came due all session: a value moves, and every picture of it is quietly stale until somebody re-shoots it. A stale picture is worse than no picture, because it looks checked. What is left is what a picture never carried anyway: the state, and the token it reads. The resting component is live and interactive above, so hover it, tab to it, and read the value off the real thing rather than off a photograph of it.

Restlight
no fill of its own, the destination inherits --text-primary, the sentence and the chevron read --text-muted
Restdark
the same two tiers, the other half of each pair. The gap between them holds in both themes, which is what keeps the sentence readable as the quieter half
Hoverlight
--bg-hover, and nothing else: no border, no shift, no size change. Four rows stack in a divided list and a border under the pointer would move the three below it
Hoverdark
the fill goes LIGHTER here and darker in the light theme: a hover moves away from its ground, and the ground swapped ends
Focus visiblelight
--color-focus, 6.23:1 as a line, at 2px offset so the ring sits outside the row
Focus visibledark
--color-focus, 6.82:1. On Settings this ring is what tells a keyboard user they are on "Sign out" rather than on "Help and support", which is the argument for the open row above
Retake, and this is the whole recipe, because there is no node Playwright in this repo and a command that does not run is worse than no command: serve the repo, then for theme in (none, data-theme="dark" on <html>): goto /design/kit/nav-row.html move the pointer away -> screenshot #live-rest -> screens/nav-row-rest-<theme>.png hover #shot-navrow -> screenshot #live-rest -> screens/nav-row-hover-<theme>.png focus #shot-navrow by Tab, assert :focus-visible -> screenshot #live-rest -> screens/nav-row-focus-<theme>.png Reached the way a person reaches them: a real pointer and a real Tab. NO FILE COMES OUT OF THIS TODAY, and the recipe is kept for the day one is wanted rather than as a promise. The strip was removed by the founder on 2026-08-11 and the states above are described instead, so there is nothing here for step 9 to diff. The earlier wording said step 9 checks these files for a byte shift; it was written before the decision and outlived it, which is the same freeze it was warning about, in prose.

The technical half

ReadsWhich tokenGrowing from
the destinationnone, it inherits--text-primary from the body. The row writes color: inherit, so there is nothing here to disagree with the page
the sentence and the chevron--text-muted--muted, the single secondary tier
hover fill--bg-hover--panel, and --panel-dark in the dark theme, which is lighter and not darker
the focus ring--color-focus--petrol
its floor--rowprimitive, straight. 56px, twelve over the 44px of --tap, which this file never reads
the two text sizes--type-body, --type-metaprimitive, straight: geometry has nothing to override
gap and padding--space-2, --space-16primitive, straight
the divider between two rowsnonethe Divided list organism. The row draws no line of its own

Lives in design/system/components/nav-row.css. Stands on 2 grey pages, 8 rows, and both of them are coloured, so every nav row in the product renders in Petrol and Paper today: Settings and Settings, no account.

<li><a class="navrow" href="connections.html"> <span>Your sources<span class="sub">Banks and manual entries you track</span></span> <span class="arrow">&rsaquo;</span> </a></li>

The unclassed span is part of the copy and not an accident of the markup: it is what gives space-between two children instead of three. The li is there for the same reason as on the subscription row, because the divider between two nav rows belongs to the list around them.