Collections
tier 2 — classes
Four ways to show a set of things. Pick by what the reader does with it: compare values
(a table), open one at a time (.list), follow an order
(.steps), read a record (.timeline), or expand into detail
(.accordion, .tree).
List
For rows where a table would be wrong: when the fields differ per row, when one field dominates and the rest supports it, or when each row is something you open rather than compare down a column.
A row that navigates is an <a class="list-row"> filling the
<li>, never a click handler on the <li> — the whole
row is then a real link, openable in a new tab and reachable by keyboard.
.list-main carries min-width:0, which is what makes the ellipsis
work: a flex item otherwise refuses to shrink below its content, and truncation silently
never happens.
<div class="card" style="max-width:520px">
<ul class="list">
<li>
<a class="list-row" href="#" aria-current="true">
<span class="avatar avatar-sm">DR</span>
<span class="list-main">
<span class="list-title">VPN disconnects every few minutes</span>
<span class="list-sub">ORD-4204 · EU-West · Alex Fischer</span>
</span>
<span class="list-meta">
<span class="badge badge-danger">P1</span>
<span>22 min</span>
</span>
</a>
</li>
<li>
<a class="list-row" href="#">
<span class="avatar avatar-sm avatar--muted"><i class="ri-robot-line"></i></span>
<span class="list-main">
<span class="list-title">Outlook will not start after the update — a title long enough to need truncating</span>
<span class="list-sub">ORD-4209 · EU-Central</span>
</span>
<span class="list-meta"><span class="badge badge-warn">P3</span><span>4 min</span></span>
</a>
</li>
</ul>
</div>
Steps
Progress through a sequence that has an order and an end — a wizard, an approval chain.
State is data-state on the <li> rather than a modifier class,
because a step has exactly one of three states and an attribute cannot accidentally carry
two. The number comes from a CSS counter, so inserting a step is not a renumbering edit.
Done is filled and pending is outlined. That difference survives the colour-blind palette, a greyscale print and forced colours — which a green-versus-grey fill would not — so no markup has to carry a tick.
- Reservation received
- Reviewed
- Awaiting approval
- Applied
<ol class="steps" style="max-width:520px">
<li data-state="done">Reservation received</li>
<li data-state="done">Reviewed</li>
<li data-state="current">Awaiting approval</li>
<li>Applied</li>
</ol>
Timeline
Things that happened, with when — an audit trail, a change history. It differs from
.steps in what it is for: steps have a fixed sequence the reader can
be “on”, a timeline is an open-ended record. If the reader can be on one of
them, it is steps.
The rule runs down the markers as a border on the <li>, so it stops
exactly at the last entry without anyone having to give it a length.
data-kind tints a marker for an entry that mattered.
- 03:15 Approved and written to the warehouse
- 02:58 Priority raised to P2 by the housekeeper
- 02:41 Rerouted to EU-West
- 01:12 First reply attempt failed — mailbox unavailable
- 00:31 Order opened from an e-mail
<ul class="timeline" style="max-width:460px">
<li data-kind="go">
<span class="timeline-when">03:15</span>
<span class="timeline-what">Approved and written to the warehouse</span>
</li>
<li data-kind="warn">
<span class="timeline-when">02:58</span>
<span class="timeline-what">Priority raised to P2 by the housekeeper</span>
</li>
<li>
<span class="timeline-when">02:41</span>
<span class="timeline-what">Rerouted to EU-West</span>
</li>
<li data-kind="danger">
<span class="timeline-when">01:12</span>
<span class="timeline-what">First reply attempt failed — mailbox unavailable</span>
</li>
<li>
<span class="timeline-when">00:31</span>
<span class="timeline-what">Order opened from an e-mail</span>
</li>
</ul>
Accordion
Built on <details>/<summary>, which is the point: the
open state, the keyboard operation and the announcement all come from the platform, so
there is no ARIA to get wrong and nothing to wire.
Give every <details> the same name to make them mutually
exclusive — that is a platform feature too, and it needs no JavaScript. Try it: opening one
below closes the others.
What the AI proposed
Reroute to EU-West, confidence 0.87, matched on “VPN” and “disconnect” in the description.
Similar orders
Four in the last 30 days, all resolved by EU-West.
Raw payload
The warehouse record as received.
<div class="accordion" style="max-width:520px">
<details name="ex-acc" open>
<summary><i class="ri-robot-line"></i> What the AI proposed</summary>
<div class="accordion-body">
<p>Reroute to EU-West, confidence 0.87, matched on “VPN” and
“disconnect” in the description.</p>
</div>
</details>
<details name="ex-acc">
<summary><i class="ri-history-line"></i> Similar orders</summary>
<div class="accordion-body">
<p>Four in the last 30 days, all resolved by EU-West.</p>
</div>
</details>
<details name="ex-acc">
<summary><i class="ri-file-list-3-line"></i> Raw payload</summary>
<div class="accordion-body">
<p>The warehouse record as received.</p>
</div>
</details>
</div>
Tree
Nested structure the reader expands — a group hierarchy, a folder of files. Nested
<ul> inside <details>, for the same reason as the
accordion.
Do not declare role="tree". A tree promises single-tab-stop
navigation with arrow keys through a flattened view, which this markup does not implement;
<details> announces a set of disclosures, which is what it is.
.tree-leaf is an item with nothing under it, indented to line up with its
siblings' labels.
Fulfilment64
Network12
- Applications3
<div class="tree" style="max-width:360px">
<ul>
<li>
<details open>
<summary><i class="ri-building-line"></i> Fulfilment<span class="tree-count">64</span></summary>
<ul>
<li><a class="tree-leaf" href="#" aria-current="true"><i class="ri-user-line"></i> Frontline<span class="tree-count">41</span></a></li>
<li><a class="tree-leaf" href="#"><i class="ri-user-line"></i> Escalation<span class="tree-count">23</span></a></li>
</ul>
</details>
</li>
<li>
<details>
<summary><i class="ri-router-line"></i> Network<span class="tree-count">12</span></summary>
<ul>
<li><a class="tree-leaf" href="#"><i class="ri-user-line"></i> On call<span class="tree-count">12</span></a></li>
</ul>
</details>
</li>
<li><a class="tree-leaf" href="#"><i class="ri-apps-line"></i> Applications<span class="tree-count">3</span></a></li>
</ul>
</div>