| Reel 3 | 42:10 |
| Mixed | 0:30 |
Table
Rows of data with printed column labels, figures right-aligned in columns, and status in lamps with words.
Kit part · Lists
Rows in a rack: a mark, a title, a second line and a fact or a key at the end. Chosen rows sink into a recess with their check key latched; in a running order, a row lifts out of the rack on its skirt and slides past the others, from the keyboard or by its grip.
Both finishes, side by side. Hover, pressed and focus are forced with .is-hover, .is-down and .is-focus; checked and disabled are real.
Aluminium
| Part | Rest | Hover | Focus | Chosen · lifted |
|---|---|---|---|---|
| Selectable |
|
|
|
|
| Reorder |
|
|
|
|
Graphite
| Part | Rest | Hover | Focus | Chosen · lifted |
|---|---|---|---|---|
| Selectable |
|
|
|
|
| Reorder |
|
|
|
|
| Name | Kind | Values | What it does |
|---|---|---|---|
| .tui-list | class | on <ul> · <ol> | The rack. Plain rows need no script. |
| .tui-list__row | class | on <li> · <a> | A row: lead, text, then a meta and/or one key. An <a> row goes somewhere as a whole. |
| .tui-list__lead | class | avatar · lamp · icon · check · number | The mark at the start, 24px wide at least. |
| .tui-list__title · __sub | class | one line each | What the row is, and one fact more. |
| .tui-list__meta | class | a short fact | Right-aligned, tabular: a time, a size, a percentage. |
| role="listbox" · tabindex="0" | attribute | on the list | Selectable rows (role="option"), one tab stop. aria-multiselectable="true" to choose several. |
| aria-selected | attribute | "true" · "false" | Chosen: the row sinks into a recess and its check key latches. |
| .tui-list__check | class | in the lead | The check key of a selectable row. |
| change | event | on the listbox | The choice changed. |
| .tui-list--reorder | class | on <ol> | A running order: rows numbered by position, a grip on each. |
| .tui-list__num | class | in the lead | Prints the row’s position, “01”, from a CSS counter. |
| .tui-list__grip | class | button, aria-label "Move …" | Knurled; lifts its row. aria-describedby the instructions. |
| tui-list-reorder | event | detail { from, to } | A row was dropped somewhere new. |
| Up · Down · Home · End | keyboard | listbox | Move the active row. |
| Space · Enter · Ctrl+A | keyboard | listbox | Choose (toggle when multiple) · choose all. |
| Space · arrows · Escape | keyboard | grip | Lift · move · put back. Space again drops. |
<!-- Plain rows. -->
<ul class="tui-list">
<li class="tui-list__row">
<span class="tui-list__lead"><span class="tui-avatar" role="img" aria-label="Ada Okafor">…</span></span>
<span class="tui-list__text"><span class="tui-list__title">Mix review</span><span class="tui-list__sub">Ada Okafor · Studio A</span></span>
<span class="tui-list__meta">14:20</span>
<button class="tui-key tui-key--sm">Join</button>
</li>
</ul>
<!-- Selectable: one tab stop, arrows and Space. -->
<ul class="tui-list" role="listbox" aria-label="Takes" aria-multiselectable="true" tabindex="0">
<li class="tui-list__row" role="option" aria-selected="true">
<span class="tui-list__lead"><span class="tui-list__check" aria-hidden="true"></span></span>
<span class="tui-list__text"><span class="tui-list__title">Take 3</span><span class="tui-list__sub">Vocal, room mic</span></span>
<span class="tui-list__meta">3:42</span>
</li>
</ul>
<!-- Reorderable: a grip per row; the numbers follow the order. -->
<p id="list-help" hidden>Space lifts the row. Arrow keys move it. Space drops it; Escape puts it back.</p>
<ol class="tui-list tui-list--reorder" aria-label="Running order">
<li class="tui-list__row">
<span class="tui-list__lead tui-list__num" aria-hidden="true"></span>
<span class="tui-list__text"><span class="tui-list__title">Intro</span><span class="tui-list__sub">Piano, room mics</span></span>
<span class="tui-list__meta">1:12</span>
<button type="button" class="tui-list__grip" aria-label="Move Intro" aria-pressed="false" aria-describedby="list-help"></button>
</li>
</ol>import '/kit/kit.mjs'; // wires every selectable and reorderable list, now and later
document.querySelector('[aria-label="Takes"]').addEventListener('change', (e) => keep(chosen(e.target)));
document.querySelector('[aria-label="Running order"]').addEventListener('tui-list-reorder', (e) => {
save(e.detail.from, e.detail.to); // indexes, 0-based
});Needs kit.css and kit.mjs. How to install the kit.
aria-activedescendant for the active row, aria-selected for chosen ones. The check key and the recess show it twice over.aria-pressed) named “Move Intro”; every lift, move, drop and cancel is announced in a live region with the new position.Plain CSS grid rows with inset hairlines; a delegated module adds the two behaviours, so lists added later work without a call. Moving a row by keyboard moves its neighbour instead, so the focused grip never leaves the DOM and never loses the focus. The numbers are a CSS counter, so they follow the order with no script. A lifted row takes the key’s skirt and a longer shadow and rises 2px; when it drops, it settles back into the rack over 120ms.
Two lines and one key per row at most; moving a row is always possible from the keyboard, and said out loud.
5 rules in this file, with the foundations they rest on and the anti-patterns that break them. Full rules ship in the brain with the Pass.
| Reel 3 | 42:10 |
| Mixed | 0:30 |
Rows of data with printed column labels, figures right-aligned in columns, and status in lamps with words.
A person’s mark, struck like a coin: initials stamped into the field, or a photo set under the rim, with a status lamp mounted at five o’clock. Stacks into a group with a count.
Folders and files as a real tree, printed like a wiring diagram: traces with an elbow into every item, chevrons that turn, and the chosen file set in a recess with its lamp lit. Written as a plain nested list.