Plan
A collapsible plan component for displaying AI-generated execution plans with streaming support and shimmer animations.
The Plan component provides a flexible system for displaying AI-generated execution plans with collapsible content. Perfect for showing multi-step workflows, task breakdowns, and implementation strategies with support for streaming content and loading states.
"use client";import { Plan, PlanAction, PlanContent, PlanDescription, PlanFooter, PlanHeader, PlanTitle, PlanTrigger,} from "@/components/ai-elements/elements/plan";import { Button } from "@/components/ui/button";import { FileText } from "lucide-react";const Example = () => ( <Plan defaultOpen={false}> <PlanHeader> <div> <div className="mb-4 flex items-center gap-2"> <FileText className="size-4" /> <PlanTitle>Rewrite AI Elements to SolidJS</PlanTitle> </div> <PlanDescription> Rewrite the AI Elements component library from React to SolidJS while maintaining compatibility with existing React-based shadcn/ui components using solid-js/compat, updating all 29 components and their test suite. </PlanDescription> </div> <PlanTrigger /> </PlanHeader> <PlanContent> <div className="space-y-4 text-sm"> <div> <h3 className="mb-2 font-semibold">Overview</h3> <p> This plan outlines the migration strategy for converting the AI Elements library from React to SolidJS, ensuring compatibility and maintaining existing functionality. </p> </div> <div> <h3 className="mb-2 font-semibold">Key Steps</h3> <ul className="list-inside list-disc space-y-1"> <li>Set up SolidJS project structure</li> <li>Install solid-js/compat for React compatibility</li> <li>Migrate components one by one</li> <li>Update test suite for each component</li> <li>Verify compatibility with shadcn/ui</li> </ul> </div> </div> </PlanContent> <PlanFooter className="justify-end"> <PlanAction> <Button size="sm"> Build <kbd className="font-mono">⌘↩</kbd> </Button> </PlanAction> </PlanFooter> </Plan>);export default Example;Installation
npx ai-elements@latest add plannpx shadcn@latest add @ai-elements/plan"use client";import { Button } from "@repo/shadcn-ui/components/ui/button";import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle,} from "@repo/shadcn-ui/components/ui/card";import { Collapsible, CollapsibleContent, CollapsibleTrigger,} from "@repo/shadcn-ui/components/ui/collapsible";import { cn } from "@repo/shadcn-ui/lib/utils";import { ChevronsUpDownIcon } from "lucide-react";import type { ComponentProps } from "react";import { createContext, useContext } from "react";import { Shimmer } from "./shimmer";type PlanContextValue = { isStreaming: boolean;};const PlanContext = createContext<PlanContextValue | null>(null);const usePlan = () => { const context = useContext(PlanContext); if (!context) { throw new Error("Plan components must be used within Plan"); } return context;};export type PlanProps = ComponentProps<typeof Collapsible> & { isStreaming?: boolean;};export const Plan = ({ className, isStreaming = false, children, ...props}: PlanProps) => ( <PlanContext.Provider value={{ isStreaming }}> <Collapsible asChild data-slot="plan" {...props}> <Card className={cn("shadow-none", className)}>{children}</Card> </Collapsible> </PlanContext.Provider>);export type PlanHeaderProps = ComponentProps<typeof CardHeader>;export const PlanHeader = ({ className, ...props }: PlanHeaderProps) => ( <CardHeader className={cn("flex items-start justify-between", className)} data-slot="plan-header" {...props} />);export type PlanTitleProps = Omit< ComponentProps<typeof CardTitle>, "children"> & { children: string;};export const PlanTitle = ({ children, ...props }: PlanTitleProps) => { const { isStreaming } = usePlan(); return ( <CardTitle data-slot="plan-title" {...props}> {isStreaming ? <Shimmer>{children}</Shimmer> : children} </CardTitle> );};export type PlanDescriptionProps = Omit< ComponentProps<typeof CardDescription>, "children"> & { children: string;};export const PlanDescription = ({ className, children, ...props}: PlanDescriptionProps) => { const { isStreaming } = usePlan(); return ( <CardDescription className={cn("text-balance", className)} data-slot="plan-description" {...props} > {isStreaming ? <Shimmer>{children}</Shimmer> : children} </CardDescription> );};export type PlanActionProps = ComponentProps<typeof CardAction>;export const PlanAction = (props: PlanActionProps) => ( <CardAction data-slot="plan-action" {...props} />);export type PlanContentProps = ComponentProps<typeof CardContent>;export const PlanContent = (props: PlanContentProps) => ( <CollapsibleContent asChild> <CardContent data-slot="plan-content" {...props} /> </CollapsibleContent>);export type PlanFooterProps = ComponentProps<"div">;export const PlanFooter = (props: PlanFooterProps) => ( <CardFooter data-slot="plan-footer" {...props} />);export type PlanTriggerProps = ComponentProps<typeof CollapsibleTrigger>;export const PlanTrigger = ({ className, ...props }: PlanTriggerProps) => ( <CollapsibleTrigger asChild> <Button className={cn("size-8", className)} data-slot="plan-trigger" size="icon" variant="ghost" {...props} > <ChevronsUpDownIcon className="size-4" /> <span className="sr-only">Toggle plan</span> </Button> </CollapsibleTrigger>);Usage
import {
Plan,
PlanAction,
PlanContent,
PlanDescription,
PlanFooter,
PlanHeader,
PlanTitle,
PlanTrigger,
} from '@/components/ai-elements/plan';<Plan defaultOpen={false}>
<PlanHeader>
<div>
<PlanTitle>Implement new feature</PlanTitle>
<PlanDescription>
Add authentication system with JWT tokens and refresh logic.
</PlanDescription>
</div>
<PlanTrigger />
</PlanHeader>
<PlanContent>
<div className="space-y-4 text-sm">
<div>
<h3 className="mb-2 font-semibold">Overview</h3>
<p>This plan outlines the implementation strategy...</p>
</div>
</div>
</PlanContent>
<PlanFooter>
<Button>Execute Plan</Button>
</PlanFooter>
</Plan>Features
- Collapsible content with smooth animations
- Streaming support with shimmer loading states
- Built on shadcn/ui Card and Collapsible components
- TypeScript support with comprehensive type definitions
- Customizable styling with Tailwind CSS
- Responsive design with mobile-friendly interactions
- Keyboard navigation and accessibility support
- Theme-aware with automatic dark mode support
- Context-based state management for streaming
Props
<Plan />
Prop
Type
<PlanHeader />
Prop
Type
<PlanTitle />
Prop
Type
<PlanDescription />
Prop
Type
<PlanTrigger />
Prop
Type
<PlanContent />
Prop
Type
<PlanFooter />
Prop
Type
<PlanAction />
Prop
Type
Open In Chat
A dropdown menu for opening queries in various AI chat platforms including ChatGPT, Claude, T3, Scira, and v0.
Prompt Input
Allows a user to send a message with file attachments to a large language model. It includes a textarea, file upload capabilities, a submit button, and a dropdown for selecting the model.