<!-- GENERATED by scripts/build-llms.mjs from llms/agent-tools.md — do not edit this file. -->

# `lr-task-list`

- **Import** `import '@aceshooting/lyra-ui/components/lr-task-list.js';` (stable tag alias; registers the tag)
- **Class** `LyraTaskList`, also available unregistered from `@aceshooting/lyra-ui/components/agent-tools/task-list/task-list.class.js`
- **Family** `components/agent-tools/` — see `llms/index.md` for its siblings
- **Status** `stable` since `4.0.0` — see the maturity and deprecation policy in `llms/shared.md`
- **Release history** [CHANGELOG.md](../../CHANGELOG.md); family-wide breaking-change summaries: [llms-full.txt](../../llms-full.txt)
- **Deprecations** none
- **Optional peers** none
- **Themeable via** 11 parts, 13 custom properties — see this component's own `@csspart`/`@cssprop` list below
- **Library-wide behavior** (events, form association, `locale`/`strings`, tokens, TS types): `llms/shared.md`

---

## `lr-task-list`

A live, collapsible tracker for an agent's plan: ordered steps with per-step lifecycle status and one
level of nested sub-steps, embedded in the transcript. `items` is controlled and never mutated by this
component. Unlike `<lr-stepper>`'s single-`current` navigation, task-list has no selection and
several steps may be `running` at once. By default it is a status report; `reorderable` adds
controlled keyboard reorder requests without changing ownership of `items`. Status changes and
confirmed moves are announced through an internal `<lr-live-region>`.

**Properties:** `items: readonly TaskItem[] = []` (attribute: false) — `TaskItem { id: string; label: string;
status: TaskStatus; detail?: string; children?: readonly TaskItem[] }` with `TaskStatus = 'pending' |
'running' | 'success' | 'error'` (both exported here). `detail` is an optional secondary plain-text
line; `children` is exactly **one** level of sub-steps — a child's own `children` is ignored with a
`console.warn`. Runtime non-record rows and rows without a nonempty string `id` are omitted before
rendering, summaries, announcements, and reorder validation. While `reorderable`, every retained
top-level task and direct child must additionally have a globally unique `id`; duplicate data stays
visible but fails closed, with no row keyboard stops or reorder requests.
`reorderable: boolean = false` (reflected) enables Ctrl/Cmd+ArrowUp/ArrowDown on a focused task.
It emits a request only; the host must assign a new reordered `items` array before the task visibly
moves or an announcement is made. `label?: string` omits into localized `taskListLabel` (`'Tasks'`
in the built-in English catalog); any supplied value is an explicit verbatim override, including
`'Tasks'` under a non-English `.strings` catalog and `''`. `headingLevel: LyraHeadingLevel = '3'`
(attribute `heading-level`, reflected) — `1`–`6` expose the visible header as that semantic heading
level around either its disclosure button or static content, invalid untyped values retain level 3,
and `none` is the explicit visual-only opt-out — `expanded: boolean = true` (reflected), and
`collapsible: boolean = true`. `compact: boolean = false` (reflected) — tighter header/body padding
and item gap for dense contexts (a plan tracker nested in an already-padded transcript row), same
convention as `<lr-agent-run>`'s/`<lr-source-card>`'s `compact`; purely a density knob, the border
and background stay. `frame: LyraFrame = 'card'` (reflected) — container treatment, in the
library-wide `frame` vocabulary (`'card' | 'plain'`); `'plain'` removes `[part="base"]`'s border,
background, and corner radius so a list embedded in a container that already draws a border (an
agent-run panel, a message bubble) doesn't double it. The exported alias `TaskListAppearance` is
retained as a name for the same union.

**Slots:** `detail-<id>` — dynamic, one per item id (e.g. `slot="detail-step-3"`); rich detail under
that item's label, typically a `<lr-tool-call-chip>` or file `<lr-chip>`.

**Events:** `lr-toggle` — the header was activated, expanding or collapsing the panel. `detail: {
expanded }`. `lr-reorder` — Ctrl/Cmd+ArrowUp/ArrowDown requests moving the focused task within its
own sibling list. `detail: { taskId, parentTaskId, fromIndex, toIndex }`; `parentTaskId` is `null`
for a top-level task and indices are sibling-scoped. It fires only while `reorderable` with unique,
nonempty ids.
A boundary key is a silent no-op, so it never reparents a child; the component announces success only
after the host's rendered array confirms the exact requested swap.

**CSS parts:** `base`, `header` (a `<button>` when `collapsible`, plain content otherwise, within
the configured semantic heading), `label`,
`summary` (the visible "N of M completed" summary, top-level items only), `toggle` (the chevron
indicator, only rendered when `collapsible`), `body` (the list of items, `hidden` while collapsed),
`item` (`role="listitem"`; carries `data-status`/`data-id`/`data-depth` and is focusable only for
valid `reorderable` data), `status-icon`, `item-label`, `item-detail`, and `item-children` (the
nested `role="list"` wrapper around a top-level item's children).

**Themeable custom properties:** `--lr-task-list-spin` (default `var(--lr-transition-ambient)`, i.e.
`1.8s ease-in-out`, collapsing to `0.001ms linear` under `prefers-reduced-motion`) — running-status
icon spin animation duration/timing; `--lr-task-list-compact-header-padding` (default
`var(--lr-space-2xs) var(--lr-space-s)`) — `[part="header"]` padding while `compact`;
`--lr-task-list-compact-header-gap` (default `var(--lr-space-2xs)`) — gap between `[part="header"]`'s
label/summary/toggle while `compact`, one step tighter than the header's uncompacted
`--lr-space-xs`, so `compact` tightens the header's _interior_ spacing and not just its padding;
`--lr-task-list-compact-header-font-size` (default `var(--lr-font-size-sm)`) — `[part="header"]`
font size while `compact`, completing the compact header's typography alongside its padding and
gap;
`--lr-task-list-compact-gap` (default `var(--lr-space-2xs)`) — gap between `[part="body"]`'s item
rows while `compact`; `--lr-task-list-compact-body-padding` (default `var(--lr-space-2xs)
var(--lr-space-s) var(--lr-space-s)`) — `[part="body"]` padding while `compact`;
`--lr-task-list-pending-color` (default `var(--lr-color-text-quiet)`),
`--lr-task-list-running-color` (default `var(--lr-color-brand)`),
`--lr-task-list-success-color` (default `var(--lr-color-success)`), and
`--lr-task-list-error-color` (default `var(--lr-color-danger)`) independently retint the matching
status icons without changing shared status tokens. `--lr-task-list-background` (default
`var(--lr-color-surface)`), `--lr-task-list-border-color` (default `var(--lr-color-border)`) and
`--lr-task-list-radius` (default `var(--lr-radius)`) retune `[part="base"]`'s card chrome without a
`::part(base)` override; the border-color hook also colors the header/body divider that
`frame="plain"` keeps.
