<Plan id="plan-simple" title="Quick Setup" description="Get started in 3 easy steps" todos={[ { "id": "1", "label": "Install dependencies", "status": "completed" }, { "id": "2", "label": "Configure environment", "status": "in_progress" }, { "id": "3", "label": "Run the app", "status": "pending" } ]}/>When the assistant breaks work into steps (a deployment pipeline, a research plan, a migration checklist) the Plan component turns that structure into a visual progress tracker. Each phase shows its status, and the overall shape of the work is scannable at a glance.
Role: State. Shows internal activity and progress. See Design Guidelines for how component roles work.
Run this once from your project root.
npx shadcn@latest add @tool-ui/planCreate a backend tool that returns a serializable plan payload.
// Backend toolimport { tool } from "ai";const showPlan = tool({ description: "Display an implementation plan to the user", inputSchema: { type: "object", properties: { task: { type: "string" } }, required: ["task"], additionalProperties: false, }, async execute({ task }) { return { id: "plan-1", title: "Implementation Plan", description: "Steps to complete: " + task, todos: [ { id: "1", label: "Analyze requirements", status: "completed" }, { id: "2", label: "Implement solution", status: "in_progress" }, { id: "3", label: "Write tests", status: "pending" }, ], }; },});Drop this into your runtime provider so tool results render as Plan.
import { type Toolkit } from "@assistant-ui/react";import { Plan } from "@/components/tool-ui/plan";import { safeParseSerializablePlan } from "@/components/tool-ui/plan/schema";import { ToolUI, createResultToolRenderer } from "@/components/tool-ui/shared";export const toolkit: Toolkit = { showPlan: { type: "backend", render: createResultToolRenderer({ safeParse: safeParseSerializablePlan, render: (parsedResult) => ( <ToolUI id={parsedResult.id}> <ToolUI.Surface> <Plan {...parsedResult} /> </ToolUI.Surface> <ToolUI.Actions> <ToolUI.LocalActions actions={[ { id: "approve", label: "Approve Plan" }, { id: "revise", label: "Request Changes", variant: "secondary" }, ]} onAction={(actionId) => console.log(actionId)} /> </ToolUI.Actions> </ToolUI> ), }), },};These snippets use assistant-ui for end-to-end wiring, but the Plan component itself is framework-agnostic at the UI layer: you can use it in any React codebase with any LLM SDK or tool-calling interface that can provide compatible props.
Progress bar and "X of Y complete" at a glance
Distinct icons for pending, in progress, completed, and cancelled
Click any todo to reveal additional context
Visual feedback when all tasks complete
Prop
Type
Use ToolUI.LocalActions to compose external actions below Plan.
Use Plan.Compact for a steps-only card body:
Prop
Type
Prop
Type
motion-safe variantsmotion-reduce overrides