---
title: Trace
description: Shows the steps an agent takes, such as reasoning, tool calls, sources, and plans, as lines that can expand, link, or open detail.
icon: list-tree
author:
  name: shadcn
  url: https://github.com/shadcn
sidebar:
  badge: New
search:
  keywords: [agent steps, tool call, reasoning, chain of thought, sources, ai elements]
related:
  - /marker
  - /message
  - /collapsible
mode: wide
---

<ComponentPreview name="trace-demo" />

<PoweredBy packages={[
  { name: 'Shadcn UI', url: 'https://ui.shadcn.com/docs/components/base/trace' },
  { name: 'Base UI', url: 'https://base-ui.com/react/components/collapsible' },
]} />

`Trace` is a list of lines. Each line has an icon, a title, and an optional description and status. A line can expand to show more detail, link to a page, or open a dialog or sheet.

Every line has the same shape, so reasoning, tool calls, sources, and plans built from `Trace` look and behave the same. Use `Trace` for the steps an agent takes inside a turn, [Message](/docs/message) for its reply, and [Marker](/docs/marker) for notes and dividers between turns.

## Installation

```package-install
npx shadcn@latest add @redpanda/trace
```

## Usage

```tsx
import {
  Trace,
  TraceCollapsible,
  TraceCollapsibleContent,
  TraceCollapsibleTrigger,
  TraceDescription,
  TraceIcon,
  TraceLine,
  TraceTitle,
} from "@/components/redpanda-ui/components/trace"
```

Use a `TraceLine` for a single step:

```tsx
<Trace>
  <TraceLine>
    <TraceIcon><SearchIcon /></TraceIcon>
    <TraceTitle>Searched for minimumReleaseAge</TraceTitle>
  </TraceLine>
</Trace>
```

Wrap the line in a `TraceCollapsible` to show more detail when it expands:

```tsx
<Trace>
  <TraceCollapsible>
    <TraceCollapsibleTrigger>
      <TraceLine>
        <TraceIcon><TerminalIcon /></TraceIcon>
        <TraceTitle>Ran node --version</TraceTitle>
      </TraceLine>
    </TraceCollapsibleTrigger>
    <TraceCollapsibleContent>v24.18.0</TraceCollapsibleContent>
  </TraceCollapsible>
</Trace>
```

## Anatomy

```text
Trace
├── TraceLine
│   ├── TraceIcon
│   ├── TraceTitle
│   ├── TraceDescription
│   └── TraceIcon
└── TraceCollapsible
    ├── TraceCollapsibleTrigger
    │   └── TraceLine
    └── TraceCollapsibleContent
```

`TraceLine` is always the line. To make a line do something, wrap it in that thing's trigger: a `TraceCollapsibleTrigger`, a link, or the trigger of a dialog, sheet, drawer, or popover.

## Status

Set `status` on `TraceLine` when a step is running, has failed, or hasn't started yet. A running title shimmers.

<ComponentPreview name="trace-status-demo" />

| Status      | Use for                                                                       |
| ----------- | ----------------------------------------------------------------------------- |
| none        | Work that is done: "Ran pnpm install".                                        |
| `"error"`   | Work that failed. Say so in the title: "Failed to run pnpm lint".             |
| `"running"` | Work in progress. Write the title in the present tense: "Running pnpm build". |
| `"pending"` | Work that has not started, such as a plan step: "Run pnpm test".              |

A pending line dims only its icon. The title keeps full contrast, so write it in the imperative to say the work hasn't started.

## Description

Put secondary text such as a diff stat, a duration, or a count in a `TraceDescription` after the `TraceTitle`. The title truncates; the description does not.

<ComponentPreview name="trace-description-demo" />

## Collapsible

Put the `TraceLine` inside `TraceCollapsibleTrigger` and the detail in `TraceCollapsibleContent`. The trigger adds a chevron that turns when the row opens.

<ComponentPreview name="trace-collapsible-demo" />

`TraceCollapsibleContent` applies `className` to the detail inside the animated panel. It owns its spacing, so wrap the children in a plain element when they need their own layout:

```tsx
<TraceCollapsibleContent>
  <div className="flex flex-wrap gap-1.5">
    <Badge variant="outline">vercel.com</Badge>
    <Badge variant="outline">github.com</Badge>
  </div>
</TraceCollapsibleContent>
```

## Open state

Rows start closed. Use `defaultOpen` on `TraceCollapsible` to start open, or `open` with `onOpenChange` to control a row. The type requires both together, so a controlled row can't freeze.

<ComponentPreview name="trace-open-demo" />

To open a row while it streams and let the reader's click win, pass `open ?? running`:

```tsx
const [open, setOpen] = useState<boolean>()

<TraceCollapsible onOpenChange={setOpen} open={open ?? running}>
  <TraceCollapsibleTrigger>
    <TraceLine status={running ? "running" : undefined}>…</TraceLine>
  </TraceCollapsibleTrigger>
  <TraceCollapsibleContent>{text}</TraceCollapsibleContent>
</TraceCollapsible>
```

## Link

Wrap the `TraceLine` in an anchor. `Trace` styles any wrapper of a line as its hit and focus target. For a new tab, use an arrow-up-right icon and add "(opens in a new tab)" with `sr-only`.

<ComponentPreview name="trace-link-demo" />

```tsx
<a href="https://docs.astro.build" rel="noreferrer" target="_blank">
  <TraceLine>
    <TraceTitle>
      Install Astro
      <span className="sr-only"> (opens in a new tab)</span>
    </TraceTitle>
    <TraceIcon><ArrowUpRightIcon /></TraceIcon>
  </TraceLine>
</a>
```

## Dialog

Wrap the `TraceLine` in the dialog's trigger. The dialog owns its open state, Escape, and focus return.

<ComponentPreview name="trace-dialog-demo" />

```tsx
<Dialog>
  <DialogTrigger>
    <TraceLine>
      <TraceTitle>Searched the web for cache keys</TraceTitle>
      <TraceIcon><ChevronRightIcon /></TraceIcon>
    </TraceLine>
  </DialogTrigger>
  <DialogContent>…</DialogContent>
</Dialog>
```

## Sheet

The same shape as the dialog. Drawer and Popover work the same way.

<ComponentPreview name="trace-sheet-demo" />

## Sources

A collapsible row whose detail is a `Trace` of link rows.

<ComponentPreview name="trace-sources-demo" />

## Chain of thought

A collapsible row with step rows inside. Set the parent's status and title from its children. Use `keepMounted` on the parent's content so nested rows keep their open state while it is closed.

<ComponentPreview name="trace-steps-demo" />

## Whole turn

Three levels: the turn, a summary, and the rows. Text between steps sits between two `Trace` lists.

<ComponentPreview name="trace-turn-demo" />

## Nesting

`Trace` has no depth limit. A `TraceCollapsibleContent` can hold another `Trace`, so the same row nests as deep as the work goes. This preview renders four levels from a recursive tree: the turn, a subagent, a group of commands, and a command with its output.

<ComponentPreview name="trace-nested-demo" />

- Each level indents 24px and titles truncate, so a deep row never overflows. It just shows less of its title.
- Put `keepMounted` on every parent's `TraceCollapsibleContent`, so the rows below a closed row keep their open state.
- Set each parent's status from its children. A failure anywhere below a row makes it an error row, so a reader can follow it down from the top.
- Depth is visual only. Rows are disclosure buttons, not a tree, so assistive technology doesn't announce the level. Past three levels, write titles that make sense on their own, or open the deepest detail in a [sheet](#sheet).

## AI SDK parts

The preview at the top of this page renders `reasoning`, `tool-*`, and `source-url` parts from an [AI SDK](https://ai-sdk.dev) `UIMessage`, and **Replay** streams the same turn through `useChat`. Map each part to a line:

| Part                                                                     | Line                                                                                                                  |
| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| `reasoning`                                                              | "Thinking" while `state` is `"streaming"`, then a collapsible "Thought" row.                                          |
| `tool-*`, `state` `"output-available"`                                   | A collapsible "Ran …" row with the output in a `CodeBlock`.                                                           |
| `tool-*`, `state` `"output-error"`                                       | A collapsible "Failed to run …" row with `status="error"`.                                                            |
| `tool-*`, `state` `"input-streaming"`, `"input-available"`, or `"approval-responded"` | "Running …" with `status="running"` while the turn streams. "Waiting to run …" with `status="pending"` once it stops. |
| `tool-*`, `state` `"approval-requested"`                                 | "Waiting for approval to run …" with `status="pending"`.                                                              |
| `tool-*`, `state` `"output-denied"`                                      | "Didn't run …" with no status.                                                                                        |
| `source-url`                                                             | One link row each, inside a collapsible "Used N sources" row. Untitled sources use the URL's hostname, or the raw URL. |

Switch on every tool `state` with a `never` default, so a state added to the AI SDK can't fall into the error row. A turn that stops while a tool waits for approval hasn't failed.

The preview's transport is a fixture. Replace it with your application's chat endpoint.

## Accessibility

`Trace` adds no roles of its own. Each line gets its semantics from the element that wraps it.

- A `TraceLine` on its own is a `span`. It is read as text and is not a tab stop.
- Wrapped in a `TraceCollapsibleTrigger`, it becomes a button with `aria-expanded`. Wrapped in a link, or in the trigger for a dialog or sheet, it takes that element's keyboard and focus behavior.
- `TraceIcon` is hidden from assistive technology, so `TraceTitle` is the accessible name. Write it as a sentence that says what happened, like "Edited trace.tsx", not just "trace.tsx".
- Status is shown with color and motion, so put it in the title too: "Running pnpm build" while it runs and "Failed to run pnpm build" when it errors.
- The shimmer on a running title stops when the reader prefers reduced motion. The title still says what is happening.

## API reference

### Trace

A list of lines. It also styles any trigger or link that wraps a `TraceLine`. Accepts all `div` props.

### TraceLine

One line: an icon and a title. It is a `span`, so it is not a button or a tab stop. Accepts all `span` props.

| Prop     | Type                                | Default | Description                             |
| -------- | ----------------------------------- | ------- | --------------------------------------- |
| `status` | `"running" \| "error" \| "pending"` | -       | The state of the work the line reports. |

### TraceIcon

A decorative icon slot, hidden from assistive technology. Before the title it names the action; after it, it is the indicator.

### TraceTitle

One sentence on one line. It truncates and shimmers while the line is running.

### TraceDescription

Secondary text after the title, such as a count or a duration. It does not truncate.

### TraceCollapsible

A row that expands. Accepts the props of [Collapsible](/docs/collapsible).

| Prop           | Type                                    | Default | Description                                             |
| -------------- | --------------------------------------- | ------- | ------------------------------------------------------- |
| `open`         | `boolean`                               | -       | The controlled open state. Pass it with `onOpenChange`. |
| `defaultOpen`  | `boolean`                               | `false` | Whether the row starts open.                            |
| `onOpenChange` | `(open: boolean, eventDetails) => void` | -       | Called when the open state changes.                     |

### TraceCollapsibleTrigger

The button that opens and closes the row. Put a `TraceLine` inside it. It adds a chevron after the line.

### TraceCollapsibleContent

The detail of a row that expands.

| Prop          | Type      | Default | Description                                                                 |
| ------------- | --------- | ------- | --------------------------------------------------------------------------- |
| `keepMounted` | `boolean` | `false` | Keep the detail mounted while closed, so nested rows keep their open state. |
| `className`   | `string`  | -       | Classes for the detail inside the animated panel. The panel takes no classes. |

## Credits

- Based on the [Shadcn UI Trace](https://ui.shadcn.com/docs/components/base/trace) component.
