Installation
tokens.css + task-list.css + button.csshead.html
<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="components/task-list/task-list.css">Basic
50%
Review refund
Waiting on approval.
Verify vendor records
Checking 12 suppliers.
Cancelled import
Stopped before writing files.
Build reorder list
7 SKUs queued.
Code
task-list.html + task-list.css
task-list
<style>
/* agent-ui / task-list — rows + capsules (formerly task-rows) */
/* agent-ui / task-rows — first-class component (promoted from host extracts). */
/* 06 Task rows */
.au-task-rows { display: grid; gap: 8px; }
.au-task-row {
background: var(--au-surface);
border: 1px solid var(--au-border-color);
border-radius: var(--au-radius-md);
padding: 12px;
}
.au-task-row > summary {
align-items: center;
cursor: pointer;
display: flex;
gap: 8px;
list-style: none;
}
@media (max-width: 640px) {
.au-task-row > summary { min-height: 40px; }
}
.au-task-row > summary::-webkit-details-marker { display: none; }
.au-task-row[open] > summary .au-task-row__meta {
color: var(--au-fg);
}
.au-task-rows .au-task-row {
animation: au-task-row-in 280ms var(--au-ease) both;
}
.au-task-rows .au-task-row:nth-child(2) { animation-delay: 40ms; }
.au-task-rows .au-task-row:nth-child(3) { animation-delay: 80ms; }
.au-task-rows .au-task-row:nth-child(4) { animation-delay: 120ms; }
@media (prefers-reduced-motion: reduce) {
.au-task-rows .au-task-row { animation: none; }
}
.au-task-row__index {
color: var(--au-fg-subtle);
font: 500 12px/1 var(--au-font-mono);
min-width: 1.2rem;
}
.au-task-row__title { color: var(--au-fg); flex: 1; font: 500 13px/1.3 var(--au-font-sans); }
.au-task-row__meta { color: var(--au-fg-muted); font: 400 12px/1.3 var(--au-font-sans); }
.au-task-row__body {
color: var(--au-fg-muted);
font: 400 13px/1.45 var(--au-font-sans);
margin: 8px 0 0;
padding-left: calc(1.2rem + 8px);
}
.au-task-capsules { display: flex; flex-wrap: wrap; gap: 8px; }
.au-task-capsule {
background: var(--au-surface);
border: 1px solid var(--au-border-color);
border-radius: var(--au-radius-pill);
color: var(--au-fg-muted);
font: 400 12px/1.3 var(--au-font-sans);
padding: 8px 12px;
}
@keyframes au-task-row-in {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}
.au-task-list { display: contents; }
/* --- status vocabulary + visual status (adopted from tool-ui Plan;
status glyphs sharpened from 21st.dev agent-elements todo-tool) ---
Each task row carries data-au-state = pending | in_progress | completed | cancelled.
The status badge encodes state by SHAPE, not just color, so it stays legible
for color-blind and low-vision readers and at a glance:
pending → hollow circle
in_progress → arrow (→)
completed → check (✓)
cancelled → hollow circle with line-through title
Defaults stay text-forward / monochrome (token-driven). */
.au-task-row__status {
position: relative;
border: 1.5px solid var(--au-border-emphasis);
border-radius: 999px;
color: var(--au-fg-muted);
flex: none;
font: 700 10px/1 var(--au-font-mono);
height: 16px;
width: 16px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.au-task-row__status::before,
.au-task-row__status::after {
position: absolute;
}
.au-task-row[data-au-state="pending"] .au-task-row__title { color: var(--au-fg-muted); }
.au-task-row[data-au-state="in_progress"] .au-task-row__status {
border-color: var(--au-action);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--au-action) 18%, transparent);
color: var(--au-action);
}
.au-task-row[data-au-state="in_progress"] .au-task-row__status::after {
content: "→";
}
.au-task-row[data-au-state="in_progress"] .au-task-row__title { color: var(--au-fg); }
.au-task-row[data-au-state="completed"] .au-task-row__status {
background: var(--au-success);
border-color: var(--au-success);
color: var(--au-on-accent);
}
.au-task-row[data-au-state="completed"] .au-task-row__status::after {
content: "✓";
}
.au-task-row[data-au-state="completed"] .au-task-row__title { color: var(--au-fg-muted); }
.au-task-row[data-au-state="cancelled"] .au-task-row__status {
background: var(--au-danger);
border-color: var(--au-danger);
}
.au-task-row[data-au-state="cancelled"] .au-task-row__title {
color: var(--au-fg-subtle);
text-decoration: line-through;
}
/* --- task progress indicator (adopted from tool-ui Plan progress) --- */
.au-task-rows__progress {
align-items: center;
display: flex;
gap: 8px;
}
.au-task-rows__progress-track {
background: var(--au-surface-muted);
border-radius: var(--au-radius-pill);
display: block;
flex: 1;
height: 4px;
overflow: hidden;
}
.au-task-rows__progress-fill {
background: var(--au-action);
border-radius: var(--au-radius-pill);
display: block;
height: 100%;
}
.au-task-rows__progress-value {
color: var(--au-fg-subtle);
font: 500 12px/1 var(--au-font-mono);
}
@media (prefers-reduced-motion: reduce) {
.au-task-rows__progress-fill { transition: none; }
}
</style>
<div class="au-task-rows" data-au-component="task-list" aria-label="Tasks"><div class="au-task-rows__progress" aria-label="Task progress"><span class="au-task-rows__progress-track" aria-hidden="true"><span class="au-task-rows__progress-fill" style="width: 50%"></span></span><span class="au-task-rows__progress-value">50%</span></div><details class="au-task-row" data-au-state="pending" open data-task-id="task-1"><summary><span class="au-task-row__index" aria-hidden="true">1</span><span class="au-task-row__status" aria-hidden="true"></span><span class="au-task-row__title">Review refund</span><span class="au-task-row__meta">pending</span></summary><p class="au-task-row__body">Waiting on approval.</p></details><details class="au-task-row" data-au-state="in_progress" open data-task-id="task-2"><summary><span class="au-task-row__index" aria-hidden="true">2</span><span class="au-task-row__status" aria-hidden="true"></span><span class="au-task-row__title">Verify vendor records</span><span class="au-task-row__meta">in progress</span></summary><p class="au-task-row__body">Checking 12 suppliers.</p></details><details class="au-task-row" data-au-state="cancelled" data-task-id="task-4"><summary><span class="au-task-row__index" aria-hidden="true">4</span><span class="au-task-row__status" aria-hidden="true"></span><span class="au-task-row__title">Cancelled import</span><span class="au-task-row__meta">cancelled</span></summary><p class="au-task-row__body">Stopped before writing files.</p></details><details class="au-task-row" data-au-state="completed" open data-task-id="task-3"><summary><span class="au-task-row__index" aria-hidden="true">3</span><span class="au-task-row__status" aria-hidden="true"></span><span class="au-task-row__title">Build reorder list</span><span class="au-task-row__meta">completed</span></summary><p class="au-task-row__body">7 SKUs queued.</p></details></div>Component contract
- Install
- tokens.css · task-list.css · button.css
- States
- Host-owned via data-au-state and documented variants
- Host
- content, state transitions, and execution behind actions
For agents
task-list.contract
# agent-ui / task-list
component: task-list
selector: .au-task-list
data_au_component: task-list
purpose: Task rows with a status vocabulary (pending/in_progress/completed/cancelled), collapsible details, and an optional progress indicator.
install:
- tokens.css
- task-list.css
- button.css when rendering actions
states: Host-owned via data-au-state and documented variants.
css_variables: Uses shared semantic tokens.
events: native form, focus, and click only — no custom events or runtime required
no_javascript: Markup and native controls remain usable without script.
host_owns: The host owns content, state transitions, and execution behind actions.
accessibility: Prefer labelled regions and text status, not color alone.
security: Escape untrusted model and tool text before insertion.
rules:
- Host owns execution, authorization, persistence, validation, and state transitions.
- Components render host-provided state; they never execute tools or imply approval.
- Escape untrusted model output, tool args, and tool output before insertion.
- Use only documented data-au-* attributes and data-au-state values.
- Keep the no-JS path usable. Do not add React, Tailwind, bundlers, or remote assets.
source: components/task-list/task-list.{html,css} + README.md + fixture.html