• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
drewmcdonald

drewmcdonald

promptCompare

Public
Like
promptCompare
Home
Code
7
.claude
3
backend
2
docs
1
frontend
4
shared
.mcp.json
deno.json
Environment variables
2
Branches
1
Pull requests
Remixes
History
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
.claude
/
skills
/
ai-elements
/
references
/
task.md
Code
/
.claude
/
skills
/
ai-elements
/
references
/
task.md
Search
…
Viewing readonly version of main branch: v149
View latest version
task.md

Task

A collapsible task list component for displaying AI workflow progress, with status indicators and optional descriptions.

The Task component provides a structured way to display task lists or workflow progress with collapsible details, status indicators, and progress tracking. It consists of a main Task container with TaskTrigger for the clickable header and TaskContent for the collapsible content area.

See scripts/task.tsx for this example.

Installation

npx ai-elements@latest add task

Usage with AI SDK

Build a mock async programming agent using experimental_generateObject.

Add the following component to your frontend:

Create val
"use client"; import { experimental_useObject as useObject } from "@ai-sdk/react"; import { Task, TaskContent, TaskItem, TaskItemFile, TaskTrigger, } from "@/components/ai-elements/task"; import { Button } from "@/components/ui/button"; import { tasksSchema } from "@/app/api/task/route"; import { SiCss, SiHtml5, SiJavascript, SiJson, SiMarkdown, SiReact, SiTypescript, } from "@icons-pack/react-simple-icons"; const iconMap = { react: { component: SiReact, color: "#149ECA" }, typescript: { component: SiTypescript, color: "#3178C6" }, javascript: { component: SiJavascript, color: "#F7DF1E" }, css: { component: SiCss, color: "#1572B6" }, html: { component: SiHtml5, color: "#E34F26" }, json: { component: SiJson, color: "#000000" }, markdown: { component: SiMarkdown, color: "#000000" }, }; const TaskDemo = () => { const { object, submit, isLoading } = useObject({ api: "/api/agent", schema: tasksSchema, }); const handleSubmit = (taskType: string) => { submit({ prompt: taskType }); }; const renderTaskItem = (item: any, index: number) => { if (item?.type === "file" && item.file) { const iconInfo = iconMap[item.file.icon as keyof typeof iconMap]; if (iconInfo) { const IconComponent = iconInfo.component; return ( <span className="inline-flex items-center gap-1" key={index}> {item.text} <TaskItemFile> <IconComponent color={item.file.color || iconInfo.color} className="size-4" /> <span>{item.file.name}</span> </TaskItemFile> </span> ); } } return item?.text || ""; }; return ( <div className="max-w-4xl mx-auto p-6 relative size-full rounded-lg border h-[600px]"> <div className="flex flex-col h-full"> <div className="flex gap-2 mb-6 flex-wrap"> <Button onClick={() => handleSubmit("React component development")} disabled={isLoading} variant="outline" > React Development </Button> </div> <div className="flex-1 overflow-auto space-y-4"> {isLoading && !object && ( <div className="text-muted-foreground">Generating tasks...</div> )} {object?.tasks?.map((task: any, taskIndex: number) => ( <Task key={taskIndex} defaultOpen={taskIndex === 0}> <TaskTrigger title={task.title || "Loading..."} /> <TaskContent> {task.items?.map((item: any, itemIndex: number) => ( <TaskItem key={itemIndex}> {renderTaskItem(item, itemIndex)} </TaskItem> ))} </TaskContent> </Task> ))} </div> </div> </div> ); }; export default TaskDemo;

Add the following route to your backend:

Create val
import { streamObject } from "ai"; import { z } from "zod"; export const taskItemSchema = z.object({ type: z.enum(["text", "file"]), text: z.string(), file: z .object({ name: z.string(), icon: z.string(), color: z.string().optional(), }) .optional(), }); export const taskSchema = z.object({ title: z.string(), items: z.array(taskItemSchema), status: z.enum(["pending", "in_progress", "completed"]), }); export const tasksSchema = z.object({ tasks: z.array(taskSchema), }); // Allow streaming responses up to 30 seconds export const maxDuration = 30; export async function POST(req: Request) { const { prompt } = await req.json(); const result = streamObject({ model: "openai/gpt-4o", schema: tasksSchema, prompt: `You are an AI assistant that generates realistic development task workflows. Generate a set of tasks that would occur during ${prompt}. Each task should have: - A descriptive title - Multiple task items showing the progression - Some items should be plain text, others should reference files - Use realistic file names and appropriate file types - Status should progress from pending to in_progress to completed For file items, use these icon types: 'react', 'typescript', 'javascript', 'css', 'html', 'json', 'markdown' Generate 3-4 tasks total, with 4-6 items each.`, }); return result.toTextStreamResponse(); }

Features

  • Visual icons for pending, in-progress, completed, and error states
  • Expandable content for task descriptions and additional information
  • Built-in progress counter showing completed vs total tasks
  • Optional progressive reveal of tasks with customizable timing
  • Support for custom content within task items
  • Full type safety with proper TypeScript definitions
  • Keyboard navigation and screen reader support

Props

<Task />

PropTypeDefaultDescription
defaultOpenbooleantrueWhether the task is open by default.
...propsReact.ComponentProps<typeof Collapsible>-Any other props are spread to the root Collapsible component.

<TaskTrigger />

PropTypeDefaultDescription
titlestringRequiredThe title of the task that will be displayed in the trigger.
...propsReact.ComponentProps<typeof CollapsibleTrigger>-Any other props are spread to the CollapsibleTrigger component.

<TaskContent />

PropTypeDefaultDescription
...propsReact.ComponentProps<typeof CollapsibleContent>-Any other props are spread to the CollapsibleContent component.

<TaskItem />

PropTypeDefaultDescription
...propsReact.ComponentProps<-Any other props are spread to the underlying div.

<TaskItemFile />

PropTypeDefaultDescription
...propsReact.ComponentProps<-Any other props are spread to the underlying div.
FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2026 Val Town, Inc.