--- title: Benefits description: Why AI Elements is the best choice for building AI chat interfaces. type: conceptual summary: Why AI Elements is the best choice for building AI chat interfaces. related: - /docs/philosophy --- # Benefits AI Elements provides a purpose-built component library for AI applications. Here's why you should use it. ## Fully Composable Every component is designed as a building block. Compose `Message`, `MessageContent`, and `MessageResponse` together to create exactly the chat UI you need. No rigid structures or forced layouts. ```tsx title="example.tsx" {text} ``` ## More Than Just Styled Components AI Elements integrates deeply with the [AI SDK](https://ai-sdk.dev/). Components understand streaming responses, handle loading states, and work seamlessly with hooks like `useChat` and `useCompletion`. * **Streaming support** - Components like `MessageResponse` handle partial markdown gracefully * **Status awareness** - UI adapts to pending, streaming, and complete states * **Type safety** - Props align with AI SDK types like `UIMessage` ## Intuitive & Developer-Friendly If you know React and TypeScript, you already know AI Elements. Components follow familiar patterns: * Standard React props with TypeScript types * Sensible defaults that work out of the box * Full control when you need it ## Accessible & Themeable Built on [shadcn/ui](https://ui.shadcn.com/), AI Elements inherits: * **WCAG 2.1 AA** accessibility baseline * **CSS variables** for easy theming * **Dark mode** support built-in * **Semantic HTML** throughout Your existing shadcn/ui theme applies automatically. ## Fast, Flexible Installation Install only what you need. The CLI adds components directly to your codebase: npm pnpm yarn bun ```bash npx ai-elements@latest add message ``` ```bash pnpm dlx ai-elements@latest add message ``` ```bash yarn dlx ai-elements@latest add message ``` ```bash bun x ai-elements@latest add message ``` * No hidden dependencies * Full source code access * Modify components freely * Tree-shaking friendly --- title: Community description: Join the AI Elements community and help shape the future of AI interfaces. type: overview summary: Join the AI Elements community and help shape the future of AI interfaces. related: - /docs/how-to-contribute --- # Community AI Elements is an open-source project built by and for developers creating AI applications. Your contributions, feedback, and participation make it better for everyone. ## Our Values ### Inclusivity Everyone is welcome regardless of experience level, background, or identity. Ask questions, share ideas, and learn together. ### Respectful Collaboration Treat others with kindness and professionalism. Disagree constructively. Help newcomers get started. ### Quality Over Quantity Focus on meaningful contributions. A well-documented bug report is more valuable than a rushed PR. ## Get Involved ### Report Issues Found a bug or have a feature request? [Open an issue](https://github.com/vercel/ai-elements/issues) on GitHub. ### Contribute Code Ready to contribute? Check out the [contribution guide](/docs/how-to-contribute) to get started. ### Share Your Work Built something with AI Elements? Share it with the community. Tag your projects and let others learn from your implementation. ### Help Others Answer questions in GitHub issues. Review pull requests. Write tutorials or blog posts about your experience. ## Code of Conduct By participating in this community, you agree to: * Be respectful and considerate * Use welcoming and inclusive language * Accept constructive criticism gracefully * Focus on what's best for the community * Show empathy toward others Harassment, discrimination, and disruptive behavior are not tolerated. ## Recognition Contributors are recognized in the project. Significant contributions may be highlighted in release notes. Your work helps developers worldwide build better AI applications. --- title: How to Contribute description: Learn how to contribute to AI Elements. type: guide summary: How to contribute to AI Elements. related: - /docs/new-components - /docs/community --- # How to Contribute AI Elements welcomes contributions from the community. Here's how you can help. ## Types of Contributions ### Bug Reports Found something broken? [Open an issue](https://github.com/vercel/ai-elements/issues) with: * A clear description of the problem * Steps to reproduce * Expected vs actual behavior * Your environment (Node version, framework, etc.) ### Documentation Help improve the docs by: * Fixing typos and unclear explanations * Adding code examples * Improving component documentation * Writing tutorials ### Bug Fixes Fix issues in existing components. Check the [open issues](https://github.com/vercel/ai-elements/issues) for bugs to tackle. ### New Components Add components that help developers build AI interfaces. See [New Components](/docs/new-components) for requirements. ### Enhancements Improve existing components with: * Better accessibility * New features * Performance improvements * Improved TypeScript types ## Getting Started 1. Fork the [repository](https://github.com/vercel/ai-elements) 2. Clone your fork: ```bash title="Terminal" git clone https://github.com/your_username_here/ai-elements.git ``` 3. Install dependencies: ```bash title="Terminal" pnpm install ``` 4. Create a branch: ```bash title="Terminal" git checkout -b feature/your_feature_name_here ``` 5. Make your changes 6. Run tests and linting: ```bash title="Terminal" pnpm test pnpm run check ``` 7. Submit a pull request ## Pull Request Guidelines * One feature or fix per PR * Write a clear description of your changes * Include screenshots for visual changes * Update documentation if needed * Ensure tests pass See the full [CONTRIBUTING.md](https://github.com/vercel/ai-elements/blob/main/.github/CONTRIBUTING.md) for detailed guidelines. --- title: Introduction description: What is AI Elements and why you should use it. type: overview summary: What AI Elements is and why you should use it. related: - /docs/benefits - /docs/philosophy - /docs/setup --- # Introduction [AI Elements](https://www.npmjs.com/package/ai-elements) is a component library and custom registry built on top of [shadcn/ui](https://ui.shadcn.com/) to help you build AI-native applications faster. It provides pre-built components like conversations, messages and more. Installing AI Elements is straightforward and can be done in a couple of ways. You can use the dedicated CLI command for the fastest setup, or integrate via the standard shadcn/ui CLI if you've already adopted shadcn's workflow. ## Quick Start Here are some basic examples of what you can achieve using components from AI Elements. ## Prerequisites Before installing AI Elements, make sure your environment meets the following requirements: * [Node.js](https://nodejs.org/en/download/), version 18 or later * A [Next.js](https://nextjs.org/) project with the [AI SDK](https://ai-sdk.dev/) installed. * [shadcn/ui](https://ui.shadcn.com/) installed in your project. If you don't have it installed, running any install command will automatically install it for you. * We also highly recommend using the [AI Gateway](https://vercel.com/docs/ai-gateway) and adding `AI_GATEWAY_API_KEY` to your `env.local` so you don't have to use an API key from every provider. AI Gateway also gives $5 in usage per month so you can experiment with models. You can obtain an API key [here](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%2Fapi-keys\&title=Get%20your%20AI%20Gateway%20key). AI Elements is built targeting React 19 (no `forwardRef` usage) and Tailwind CSS 4. ## Installing Components You can install AI Elements components using either the AI Elements CLI or the shadcn/ui CLI. Both achieve the same result: adding the selected component’s code and any needed dependencies to your project. The CLI will download the component’s code and integrate it into your project’s directory (usually under your components folder). By default, AI Elements components are added to the `@/components/ai-elements/` directory (or whatever folder you’ve configured in your shadcn components settings). After running the command, you should see a confirmation in your terminal that the files were added. You can then proceed to use the component in your code. --- title: New Components description: Guidelines for proposing and building new AI Elements components. type: guide summary: Guidelines for proposing and building new AI Elements components. prerequisites: - /docs/how-to-contribute related: - /docs/how-to-contribute --- # New Components Want to add a new component to AI Elements? This guide covers what we look for and how to submit. ## Fit & Scope Before building, consider whether the component: ### Solves an AI-Specific Need Components should address challenges unique to AI interfaces: * Chat and conversation UIs * Streaming content display * Model status and feedback * AI-specific interactions (regenerate, branch, etc.) ### Doesn't Already Exist Check if shadcn/ui or another library already provides what you need. AI Elements focuses on components that require AI-specific behavior. ### Has Broad Applicability The component should be useful across different AI applications, not just your specific use case. ## Design Requirements ### Composability Build components from smaller pieces: ```tsx title="example.tsx" // Good: Composable {text} // Avoid: Monolithic ``` ### Consistency Follow existing patterns in the library: * Use `cn()` for class merging * Extend HTML primitive attributes * Use CSS variables for theming * Match naming conventions ### Accessibility Components must be: * Keyboard navigable * Screen reader friendly * WCAG 2.1 AA compliant * Properly labeled ## Documentation Requirements Every component needs: 1. **MDX documentation** with title and description 2. **Props table** documenting all props 3. **Usage examples** showing AI SDK integration 4. **Installation instructions** ## Technical Standards ### TypeScript * Export all prop types * Use proper generics where needed * Avoid `any` types ### Testing * Add unit tests for component logic * Test accessibility with automated tools * Verify behavior with AI SDK hooks ### Code Style * Follow the project's Biome configuration * Run `pnpm run check` before submitting * Match existing component patterns ## Submission Process 1. **Open an issue first** - Describe the component and its use case. Get feedback before building. 2. **Build the component** - Follow the patterns in `packages/elements/src/`. 3. **Add examples** - Create examples in `packages/examples/src/`. 4. **Write documentation** - Add MDX docs in `apps/docs/content/components/`. 5. **Submit a PR** - Reference the original issue. Include screenshots or videos of the component in action. ## Review Process Maintainers will review for: * Alignment with library goals * Code quality and patterns * Documentation completeness * Accessibility compliance * AI SDK integration Expect feedback and iteration. Quality components take time to get right. --- title: Philosophy description: The principles that guide AI Elements design and development. type: conceptual summary: The principles that guide AI Elements design and development. related: - /docs/benefits --- # Philosophy AI Elements is built on core principles that shape every component and decision. ## Composability Components are building blocks, not black boxes. You combine small, focused pieces to create exactly what you need. ```tsx title="example.tsx" {text} ``` This approach gives you: * **Flexibility** - Add, remove, or rearrange pieces * **Control** - Style and configure each part independently * **Clarity** - Understand exactly what renders ## Simplicity Do one thing well. Components have a clear purpose and minimal API surface. We avoid: * Unnecessary props and options * Complex configuration objects * Hidden behavior When in doubt, we leave it out. You can always extend components in your codebase. ## Accessibility Every component follows accessibility best practices: * Semantic HTML elements * Proper ARIA attributes * Keyboard navigation * Screen reader support * Sufficient color contrast Accessibility isn't an afterthought—it's built into component architecture from the start. ## Performance Components are optimized for real-world AI applications: * Minimal re-renders during streaming * Efficient DOM updates * Tree-shakeable exports * No runtime CSS-in-JS ## Developer Experience Building AI interfaces should feel natural: * **Familiar patterns** - Standard React props and hooks * **TypeScript first** - Full type safety and autocomplete * **Good defaults** - Works out of the box * **Full control** - Customize when needed ## AI SDK Alignment Components integrate deeply with the [AI SDK](https://ai-sdk.dev/): * Props match AI SDK types * Hooks work seamlessly * Streaming behavior is handled correctly * Status states are built-in ## shadcn/ui Foundation AI Elements builds on [shadcn/ui](https://ui.shadcn.com/) conventions: * Components live in your codebase * CSS variables for theming * Tailwind CSS for styling * Copy-paste friendly Your existing shadcn/ui setup and theme apply automatically. ## Open Source AI Elements is open source and community-driven: * Transparent development * Community contributions welcome * No vendor lock-in * Apache 2.0 license --- title: Setup description: Get AI Elements installed and running in your project. type: guide summary: Get AI Elements installed and running in your project. related: - /docs/usage - /docs/troubleshooting --- # Setup This guide walks you through setting up AI Elements in your project. ## Prerequisites Before installing AI Elements, ensure your environment meets these requirements: * **Node.js** 18 or later * **React** 19 * **Next.js** 14+ (App Router recommended) * **AI SDK** installed and configured * **shadcn/ui** initialized in your project * **Tailwind CSS** 4 If you don't have shadcn/ui installed, running any AI Elements install command will automatically set it up for you. ## AI Gateway (Recommended) We recommend using [AI Gateway](https://vercel.com/docs/ai-gateway) for model access as it offers a single API key for multiple model providers, built-in fallback support, unified billing and more. Add `AI_GATEWAY_API_KEY` to your `.env.local` file. [Get your API key here](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%2Fapi-keys\&title=Get%20your%20AI%20Gateway%20key). ## Installing Components Use the AI Elements CLI to add components: npm pnpm yarn bun ```bash npx ai-elements@latest add message ``` ```bash pnpm dlx ai-elements@latest add message ``` ```bash yarn dlx ai-elements@latest add message ``` ```bash bun x ai-elements@latest add message ``` Or use the shadcn CLI: npm pnpm yarn bun ```bash npx shadcn@latest add @ai-elements/message ``` ```bash pnpm dlx shadcn@latest add @ai-elements/message ``` ```bash yarn dlx shadcn@latest add @ai-elements/message ``` ```bash bun x shadcn@latest add @ai-elements/message ``` Components are added to `@/components/ai-elements/` by default. ## Verify Installation After installing a component, verify it works: 1. Check that the component file exists in your components directory 2. Import and use it in a page: ```tsx title="app/page.tsx" import { Message, MessageContent, MessageResponse, } from "@/components/ai-elements/message"; export default function Page() { return ( Hello, world! ); } ``` 3. Run your development server and confirm the component renders ## Next Steps * Learn how to [use components](/docs/usage) in your application * Browse available [components](/components) to find what you need * Check [troubleshooting](/docs/troubleshooting) if you run into issues --- title: Skill description: Enhance your AI coding agent with knowledge about AI Elements. type: integration summary: Enhance your AI coding agent with knowledge about AI Elements. prerequisites: - /docs/setup --- # Skill We maintain a [skill](https://skills.sh/) that gives your AI coding agent procedural knowledge about how to use AI Elements. ## What is a Skill? Skills are curated knowledge packages that enhance AI coding agents. When you install a skill, your agent gains context about specific libraries, patterns, and best practices—so it can help you more effectively. ## Installation Install the AI Elements skill with: ```bash title="Terminal" npx skills add vercel/ai-elements ``` Once installed, your agent understands: * How to install and use AI Elements components * Composable component patterns * AI SDK integration conventions * shadcn/ui theming and styling * Troubleshooting common issues ## Browse More Skills Visit [skills.sh](https://skills.sh/) to discover skills for other libraries and frameworks. --- title: Troubleshooting description: What to do if you run into issues with AI Elements. type: troubleshooting summary: Common issues and solutions when working with AI Elements. prerequisites: - /docs/setup --- # Troubleshooting ## Why are my components not styled? Make sure your project is configured correctly for shadcn/ui in Tailwind 4 - this means having a `globals.css` file that imports Tailwind and includes the shadcn/ui base styles. ## I ran the AI Elements CLI but nothing was added to my project Double-check that: * Your current working directory is the root of your project (where `package.json` lives). * Your components.json file (if using shadcn-style config) is set up correctly. * You’re using the latest version of the AI Elements CLI: ```bash title="Terminal" npx ai-elements@latest ``` If all else fails, feel free to open an [issue on GitHub](https://github.com/vercel/ai-elements/issues). ## Theme switching doesn’t work — my app stays in light mode Ensure your app is using the same data-theme system that shadcn/ui and AI Elements expect. The default implementation toggles a data-theme attribute on the `` element. Make sure your tailwind.config.js is using class or data- selectors accordingly: ## The component imports fail with “module not found” Check the file exists. If it does, make sure your `tsconfig.json` has a proper paths alias for `@/` i.e. ```json title="tsconfig.json" { "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./*"] } } } ``` ## My AI coding assistant can't access AI Elements components 1. Verify your config file syntax is valid JSON. 2. Check that the file path is correct for your AI tool. 3. Restart your coding assistant after making changes. 4. Ensure you have a stable internet connection. ## Still stuck? If none of these answers help, open an [issue on GitHub](https://github.com/vercel/ai-elements/issues) and someone will be happy to assist. --- title: Usage description: Learn how to use AI Elements components in your application. type: guide summary: How to use AI Elements components in your application. prerequisites: - /docs/setup related: - /docs/troubleshooting --- # Usage Once an AI Elements component is installed, you can import it and use it in your application like any other React component. The components are added as part of your codebase (not hidden in a library), so the usage feels very natural. ## Example After installing AI Elements components, you can use them in your application like any other React component. For example: ```tsx title="conversation.tsx" "use client"; import { Message, MessageContent, MessageResponse, } from "@/components/ai-elements/message"; import { useChat } from "@ai-sdk/react"; const Example = () => { const { messages } = useChat(); return ( <> {messages.map(({ role, parts }, index) => ( {parts.map((part, i) => { switch (part.type) { case "text": return ( {part.text} ); } })} ))} ); }; export default Example; ``` In the example above, we import the `Message` component from our AI Elements directory and include it in our JSX. Then, we compose the component with the `MessageContent` and `MessageResponse` subcomponents. You can style or configure the component just as you would if you wrote it yourself – since the code lives in your project, you can even open the component file to see how it works or make custom modifications. ## Extensibility All AI Elements components take as many primitive attributes as possible. For example, the `Message` component extends `HTMLAttributes`, so you can pass any props that a `div` supports. This makes it easy to extend the component with your own styles or functionality. ## Customization If you re-install AI Elements by rerunning `npx ai-elements@latest`, the CLI will ask before overwriting the file so you can save any custom changes you made. After installation, no additional setup is needed. The component’s styles (Tailwind CSS classes) and scripts are already integrated. You can start interacting with the component in your app immediately. For example, if you'd like to remove the rounding on `Message`, you can go to `components/ai-elements/message.tsx` and remove `rounded-lg` as follows: ```tsx title="components/ai-elements/message.tsx" highlight="8" export const MessageContent = ({ children, className, ...props }: MessageContentProps) => (
{children}
); ``` --- title: The Vercel AI Frontend Stack description: How AI Gateway, AI SDK, and AI Elements work together. type: conceptual summary: How AI Gateway, AI SDK, and AI Elements work together. related: - /docs/setup --- # The Vercel AI Frontend Stack Vercel provides a complete stack for building AI-powered applications. Here's how the pieces fit together. ## The Stack ## AI Gateway [AI Gateway](https://vercel.com/docs/ai-gateway) is your single point of access to AI models. ### What It Does * **Unified API** - One API key for OpenAI, Anthropic, Google, and more * **Caching** - Reduce costs by caching identical requests * **Rate limiting** - Protect your application from abuse * **Observability** - Monitor usage, latency, and costs * **Fallbacks** - Automatically retry with backup models ### Setup Add `AI_GATEWAY_API_KEY` to your environment: ```bash title=".env.local" AI_GATEWAY_API_KEY=your_api_key_here ``` Then use it with the AI SDK by specifying a model string e.g. `anthropic/claude-sonnet-4.5`. ## AI SDK The [AI SDK](https://ai-sdk.dev/) provides the foundation for AI interactions. ### Core Features * **Streaming** - Stream responses from any model * **Tool calling** - Let models call functions * **Structured output** - Get typed responses * **Multi-modal** - Handle text, images, and files ### React Hooks ```tsx title="example.tsx" "use client"; import { useChat } from "@ai-sdk/react"; function Chat() { const [text, setText] = useState(""); const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: "/api/chat", }), }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); sendMessage({ text: text }); setText(""); }; return (
{messages.map((m) => (
{m.content}
))} setText(e.target.value)} />
); } ``` ### Server Integration ```ts title="app/api/chat/route.ts" import { streamText } from "ai"; export async function POST(req: Request) { const { messages } = await req.json(); const result = streamText({ model: "anthropic/claude-sonnet-4.5", system: "You are a helpful assistant.", messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse(); } ``` ## AI Elements AI Elements provides the UI layer on top of the AI SDK. ### What It Adds * **Pre-built components** - Message, Conversation, PromptInput, and more * **Streaming support** - Components handle partial content gracefully * **Composable design** - Build exactly the UI you need * **Theme integration** - Works with your existing shadcn/ui setup ### Integration Example ```tsx title="app/chat/page.tsx" "use client"; import { useChat } from "@ai-sdk/react"; import { Conversation, ConversationContent, } from "@/components/ai-elements/conversation"; import { Message, MessageContent, MessageResponse, } from "@/components/ai-elements/message"; import { PromptInput, PromptInputBody, PromptInputFooter, PromptInputProvider, PromptInputSubmit, PromptInputTextarea, } from "@/components/ai-elements/prompt-input"; export default function ChatPage() { const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: "/api/chat", }), }); const handleSubmit = (message: { text: string }) => { sendMessage({ text: message.text }); }; return (
{messages.map((message) => ( {message.parts.map((part, i) => part.type === "text" ? ( {part.text} ) : null )} ))}
); } ``` ## Putting It Together The full flow: 1. **User types** in an AI Elements `PromptInput` 2. **React hook** (`useChat`) sends the message to your API route 3. **AI SDK** streams the response from the model via AI Gateway 4. **AI Elements** renders the streaming response in `MessageResponse` Each layer handles its responsibility: | Layer | Responsibility | | ----------- | ------------------------------------- | | AI Gateway | Model access, caching, observability | | AI SDK | Streaming, hooks, server integration | | AI Elements | UI components, theming, accessibility | This separation means you can swap any layer independently. Use a different model provider, build custom hooks, or create your own components—the stack remains flexible. --- title: Attachments description: A flexible, composable attachment component for displaying files, images, videos, audio, and source documents. --- # Attachments The `Attachment` component provides a unified way to display file attachments and source documents with multiple layout variants. ## Installation ## Usage with AI SDK Display user-uploaded files in chat messages or input areas. ```tsx title="app/page.tsx" "use client"; import { Attachments, Attachment, AttachmentPreview, AttachmentInfo, AttachmentRemove, } from "@/components/ai-elements/attachments"; import type { FileUIPart } from "ai"; interface MessageProps { attachments: (FileUIPart & { id: string })[]; onRemove?: (id: string) => void; } const MessageAttachments = ({ attachments, onRemove }: MessageProps) => ( {attachments.map((file) => ( onRemove(file.id) : undefined} > ))} ); export default MessageAttachments; ``` ## Features * Three display variants: grid (thumbnails), inline (badges), and list (rows) * Supports both FileUIPart and SourceDocumentUIPart from the AI SDK * Automatic media type detection (image, video, audio, document, source) * Hover card support for inline previews * Remove button with customizable callback * Composable architecture for maximum flexibility * Accessible with proper ARIA labels * TypeScript support with exported utility functions ## Examples ### Grid Variant Best for displaying attachments in messages with visual thumbnails. ### Inline Variant Best for compact badge-style display in input areas with hover previews. ### List Variant Best for file lists with full metadata display. ## Props ### `` Container component that sets the layout variant. ", }, }} /> ### `` Individual attachment item wrapper. void", optional: true, }, "...props": { description: "Spread to the underlying div element.", type: "React.HTMLAttributes", }, }} /> ### `` Displays the media preview (image, video, or icon). ", }, }} /> ### `` Displays the filename and optional media type. ", }, }} /> ### `` Remove button that appears on hover. ", }, }} /> ### `` Wrapper for hover preview functionality. ", }, }} /> ### `` Trigger element for the hover card. ", }, }} /> ### `` Content displayed in the hover card. ", }, }} /> ### `` Empty state component when no attachments are present. ", }, }} /> ## Utility Functions ### `getMediaCategory(data)` Returns the media category for an attachment. ```tsx import { getMediaCategory } from "@/components/ai-elements/attachments"; const category = getMediaCategory(attachment); // Returns: "image" | "video" | "audio" | "document" | "source" | "unknown" ``` ### `getAttachmentLabel(data)` Returns the display label for an attachment. ```tsx import { getAttachmentLabel } from "@/components/ai-elements/attachments"; const label = getAttachmentLabel(attachment); // Returns filename or fallback like "Image" or "Attachment" ``` --- title: Chain of Thought description: A collapsible component that visualizes AI reasoning steps with support for search results, images, and step-by-step progress indicators. --- # Chain of Thought The `ChainOfThought` component provides a visual representation of an AI's reasoning process, showing step-by-step thinking with support for search results, images, and progress indicators. It helps users understand how AI arrives at conclusions. ## Installation ## Features * Collapsible interface with smooth animations powered by Radix UI * Step-by-step visualization of AI reasoning process * Support for different step statuses (complete, active, pending) * Built-in search results display with badge styling * Image support with captions for visual content * Custom icons for different step types * Context-aware components using React Context API * Fully typed with TypeScript * Accessible with keyboard navigation support * Responsive design that adapts to different screen sizes * Smooth fade and slide animations for content transitions * Composable architecture for flexible customization ## Props ### `` void", }, "...props": { description: "Any other props are spread to the root div element.", type: 'React.ComponentProps<"div">', }, }} /> ### `` ", }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ', }, }} /> --- title: Checkpoint description: A simple component for marking conversation history points and restoring the chat to a previous state. --- # Checkpoint The `Checkpoint` component provides a way to mark specific points in a conversation history and restore the chat to that state. Inspired by VSCode's Copilot checkpoint feature, it allows users to revert to an earlier conversation state while maintaining a clear visual separation between different conversation segments. ## Installation ## Features * Simple flex layout with icon, trigger, and separator * Visual separator line for clear conversation breaks * Clickable restore button for reverting to checkpoint * Customizable icon (defaults to BookmarkIcon) * Keyboard accessible with proper ARIA labels * Responsive design that adapts to different screen sizes * Seamless light/dark theme integration ## Usage with AI SDK Build a chat interface with conversation checkpoints that allow users to restore to previous states. Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { useState, Fragment } from "react"; import { useChat } from "@ai-sdk/react"; import { Checkpoint, CheckpointIcon, CheckpointTrigger, } from "@/components/ai-elements/checkpoint"; import { Message, MessageContent, MessageResponse, } from "@/components/ai-elements/message"; import { Conversation, ConversationContent, } from "@/components/ai-elements/conversation"; type CheckpointType = { id: string; messageIndex: number; timestamp: Date; messageCount: number; }; const CheckpointDemo = () => { const { messages, setMessages } = useChat(); const [checkpoints, setCheckpoints] = useState([]); const createCheckpoint = (messageIndex: number) => { const checkpoint: CheckpointType = { id: nanoid(), messageIndex, timestamp: new Date(), messageCount: messageIndex + 1, }; setCheckpoints([...checkpoints, checkpoint]); }; const restoreToCheckpoint = (messageIndex: number) => { // Restore messages to checkpoint state setMessages(messages.slice(0, messageIndex + 1)); // Remove checkpoints after this point setCheckpoints(checkpoints.filter((cp) => cp.messageIndex <= messageIndex)); }; return (
{messages.map((message, index) => { const checkpoint = checkpoints.find( (cp) => cp.messageIndex === index ); return ( {message.content} {checkpoint && ( restoreToCheckpoint(checkpoint.messageIndex) } > Restore checkpoint )} ); })}
); }; export default CheckpointDemo; ``` ## Use Cases ### Manual Checkpoints Allow users to manually create checkpoints at important conversation points: ```tsx ``` ### Automatic Checkpoints Create checkpoints automatically after significant conversation milestones: ```tsx useEffect(() => { // Create checkpoint every 5 messages if (messages.length > 0 && messages.length % 5 === 0) { createCheckpoint(messages.length - 1); } }, [messages.length]); ``` ### Branching Conversations Use checkpoints to enable conversation branching where users can explore different conversation paths: ```tsx const restoreAndBranch = (messageIndex: number) => { // Save current branch const currentBranch = messages.slice(messageIndex + 1); saveBranch(currentBranch); // Restore to checkpoint restoreToCheckpoint(messageIndex); }; ``` ## Props ### `` ", }, }} /> ### `` ### `` ", }, }} /> --- title: Confirmation description: An alert-based component for managing tool execution approval workflows with request, accept, and reject states. --- # Confirmation The `Confirmation` component provides a flexible system for displaying tool approval requests and their outcomes. Perfect for showing users when AI tools require approval before execution, and displaying the approval status afterward. ## Installation ## Usage with AI SDK Build a chat UI with tool approval workflow where dangerous tools require user confirmation before execution. Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { useChat } from "@ai-sdk/react"; import { DefaultChatTransport, type ToolUIPart } from "ai"; import { useState } from "react"; import { CheckIcon, XIcon } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Confirmation, ConfirmationTitle, ConfirmationRequest, ConfirmationAccepted, ConfirmationRejected, ConfirmationActions, ConfirmationAction, } from "@/components/ai-elements/confirmation"; import { MessageResponse } from "@/components/ai-elements/message"; type DeleteFileInput = { filePath: string; confirm: boolean; }; type DeleteFileToolUIPart = ToolUIPart<{ delete_file: { input: DeleteFileInput; output: { success: boolean; message: string }; }; }>; const Example = () => { const { messages, sendMessage, status, addToolApprovalResponse } = useChat({ transport: new DefaultChatTransport({ api: "/api/chat", }), }); const handleDeleteFile = () => { sendMessage({ text: "Delete the file at /tmp/example.txt" }); }; const latestMessage = messages[messages.length - 1]; const deleteTool = latestMessage?.parts?.find( (part) => part.type === "tool-delete_file" ) as DeleteFileToolUIPart | undefined; return (
{deleteTool?.approval && ( This tool wants to delete:{" "} {deleteTool.input?.filePath}
Do you approve this action?
You approved this tool execution You rejected this tool execution addToolApprovalResponse({ id: deleteTool.approval!.id, approved: false, }) } > Reject addToolApprovalResponse({ id: deleteTool.approval!.id, approved: true, }) } > Approve
)} {deleteTool?.output && ( {deleteTool.output.success ? deleteTool.output.message : `Error: ${deleteTool.output.message}`} )}
); }; export default Example; ``` Add the following route to your backend: ```ts title="app/api/chat/route.tsx" import { streamText, UIMessage, convertToModelMessages } from "ai"; import { z } from "zod"; // Allow streaming responses up to 30 seconds export const maxDuration = 30; export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } = await req.json(); const result = streamText({ model: "openai/gpt-4o", messages: await convertToModelMessages(messages), tools: { delete_file: { description: "Delete a file from the file system", parameters: z.object({ filePath: z.string().describe("The path to the file to delete"), confirm: z .boolean() .default(false) .describe("Confirmation that the user wants to delete the file"), }), requireApproval: true, // Enable approval workflow execute: async ({ filePath, confirm }) => { if (!confirm) { return { success: false, message: "Deletion not confirmed", }; } // Simulate file deletion await new Promise((resolve) => setTimeout(resolve, 500)); return { success: true, message: `Successfully deleted ${filePath}`, }; }, }, }, }); return result.toUIMessageStreamResponse(); } ``` ## Features * Context-based state management for approval workflow * Conditional rendering based on approval state * Support for approval-requested, approval-responded, output-denied, and output-available states * Built on shadcn/ui Alert and Button components * TypeScript support with comprehensive type definitions * Customizable styling with Tailwind CSS * Keyboard navigation and accessibility support * Theme-aware with automatic dark mode support ## Examples ### Approval Request State Shows the approval request with action buttons when state is `approval-requested`. ### Approved State Shows the accepted status when user approves and state is `approval-responded` or `output-available`. ### Rejected State Shows the rejected status when user rejects and state is `output-denied`. ## Props ### `` ", }, }} /> ### `` A styled description element for displaying a title or label within the confirmation alert. ", }, }} /> ### `` ### `` ### `` ### `` ', }, }} /> ### `` ", }, }} /> --- title: Context description: A compound component system for displaying AI model context window usage, token consumption, and cost estimation. --- # Context The `Context` component provides a comprehensive view of AI model usage through a compound component system. It displays context window utilization, token consumption breakdown (input, output, reasoning, cache), and cost estimation in an interactive hover card interface. ## Installation ## Features * **Compound Component Architecture**: Flexible composition of context display elements * **Visual Progress Indicator**: Circular SVG progress ring showing context usage percentage * **Token Breakdown**: Detailed view of input, output, reasoning, and cached tokens * **Cost Estimation**: Real-time cost calculation using the `tokenlens` library * **Intelligent Formatting**: Automatic token count formatting (K, M, B suffixes) * **Interactive Hover Card**: Detailed information revealed on hover * **Context Provider Pattern**: Clean data flow through React Context API * **TypeScript Support**: Full type definitions for all components * **Accessible Design**: Proper ARIA labels and semantic HTML * **Theme Integration**: Uses currentColor for automatic theme adaptation ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### Usage Components All usage components (`ContextInputUsage`, `ContextOutputUsage`, `ContextReasoningUsage`, `ContextCacheUsage`) share the same props: ", }, }} /> ## Component Architecture The Context component uses a compound component pattern with React Context for data sharing: 1. **``** - Root provider component that holds all context data 2. **``** - Interactive trigger element (default: button with percentage) 3. **``** - Hover card content container 4. **``** - Header section with progress visualization 5. **``** - Body section for usage breakdowns 6. **``** - Footer section for total cost 7. **Usage Components** - Individual token usage displays (Input, Output, Reasoning, Cache) ## Token Formatting The component uses `Intl.NumberFormat` with compact notation for automatic formatting: * Under 1,000: Shows exact count (e.g., "842") * 1,000+: Shows with K suffix (e.g., "32K") * 1,000,000+: Shows with M suffix (e.g., "1.5M") * 1,000,000,000+: Shows with B suffix (e.g., "2.1B") ## Cost Calculation When a `modelId` is provided, the component automatically calculates costs using the `tokenlens` library: * **Input tokens**: Cost based on model's input pricing * **Output tokens**: Cost based on model's output pricing * **Reasoning tokens**: Special pricing for reasoning-capable models * **Cached tokens**: Reduced pricing for cached input tokens * **Total cost**: Sum of all token type costs Costs are formatted using `Intl.NumberFormat` with USD currency. ## Styling The component uses Tailwind CSS classes and follows your design system: * Progress indicator uses `currentColor` for theme adaptation * Hover card has customizable width and padding * Footer has a secondary background for visual separation * All text sizes use the `text-xs` class for consistency * Muted foreground colors for secondary information --- title: Conversation description: Wraps messages and automatically scrolls to the bottom. Also includes a scroll button that appears when not at the bottom. --- # Conversation The `Conversation` component wraps messages and automatically scrolls to the bottom. Also includes a scroll button that appears when not at the bottom. ## Installation ## Usage with AI SDK Build a simple conversational UI with `Conversation` and [`PromptInput`](/components/prompt-input): Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { Conversation, ConversationContent, ConversationDownload, ConversationEmptyState, ConversationScrollButton, } from "@/components/ai-elements/conversation"; import { Message, MessageContent, MessageResponse, } from "@/components/ai-elements/message"; import { PromptInput, type PromptInputMessage, PromptInputTextarea, PromptInputSubmit, } from "@/components/ai-elements/prompt-input"; import { MessageSquare } from "lucide-react"; import { useState } from "react"; import { useChat } from "@ai-sdk/react"; const ConversationDemo = () => { const [input, setInput] = useState(""); const { messages, sendMessage, status } = useChat(); const handleSubmit = (message: PromptInputMessage) => { if (message.text.trim()) { sendMessage({ text: message.text }); setInput(""); } }; return (
{messages.length === 0 ? ( } title="Start a conversation" description="Type a message below to begin chatting" /> ) : ( messages.map((message) => ( {message.parts.map((part, i) => { switch (part.type) { case "text": // we don't use any reasoning or tool calls in this example return ( {part.text} ); default: return null; } })} )) )} setInput(e.currentTarget.value)} className="pr-12" />
); }; export default ConversationDemo; ``` Add the following route to your backend: ```tsx title="api/chat/route.ts" import { streamText, UIMessage, convertToModelMessages } from "ai"; // Allow streaming responses up to 30 seconds export const maxDuration = 30; export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } = await req.json(); const result = streamText({ model: "openai/gpt-4o", messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse(); } ``` ## Features * Automatic scrolling to the bottom when new messages are added * Smooth scrolling behavior with configurable animation * Scroll button that appears when not at the bottom * Download conversation as Markdown * Responsive design with customizable padding and spacing * Flexible content layout with consistent message spacing * Accessible with proper ARIA roles for screen readers * Customizable styling through className prop * Support for any number of child message components ## Props ### `` ", }, instance: { description: "Optional instance for controlling the StickToBottom component.", type: "StickToBottomInstance", }, children: { description: "Render prop or ReactNode for custom rendering with context.", type: "((context: StickToBottomContext) => ReactNode) | ReactNode", }, "...props": { description: "Any other props are spread to the root div.", type: 'Omit, "children">', }, }} /> ### `` ReactNode) | ReactNode", }, "...props": { description: "Any other props are spread to the root div.", type: 'Omit, "children">', }, }} /> ### `` ', }, }} /> ### `` ", }, }} /> ### `` A button that downloads the conversation as a Markdown file. ```tsx import { ConversationDownload } from "@/components/ai-elements/conversation"; {messages.map(...)} ``` string", }, "...props": { description: "Any other props are spread to the underlying shadcn/ui Button component.", type: "Omit, 'onClick'>", }, }} /> ### `messagesToMarkdown` A utility function to convert messages to Markdown format. Useful for custom download implementations. ```tsx import { messagesToMarkdown } from "@/components/ai-elements/conversation"; const markdown = messagesToMarkdown(messages); // With custom formatter const customMarkdown = messagesToMarkdown( messages, (msg, i) => `[${msg.role}]: ${msg.parts .filter((p) => p.type === "text") .map((p) => p.text) .join("")}` ); ``` --- title: Inline Citation description: A hoverable citation component that displays source information and quotes inline with text, perfect for AI-generated content with references. --- # Inline Citation The `InlineCitation` component provides a way to display citations inline with text content, similar to academic papers or research documents. It consists of a citation pill that shows detailed source information on hover, making it perfect for AI-generated content that needs to reference sources. ## Installation ## Usage with AI SDK Build citations for AI-generated content using [`experimental_generateObject`](/docs/reference/ai-sdk-ui/use-object). Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { experimental_useObject as useObject } from "@ai-sdk/react"; import { InlineCitation, InlineCitationText, InlineCitationCard, InlineCitationCardTrigger, InlineCitationCardBody, InlineCitationCarousel, InlineCitationCarouselContent, InlineCitationCarouselItem, InlineCitationCarouselHeader, InlineCitationCarouselIndex, InlineCitationCarouselPrev, InlineCitationCarouselNext, InlineCitationSource, InlineCitationQuote, } from "@/components/ai-elements/inline-citation"; import { Button } from "@/components/ui/button"; import { citationSchema } from "@/app/api/citation/route"; const CitationDemo = () => { const { object, submit, isLoading } = useObject({ api: "/api/citation", schema: citationSchema, }); const handleSubmit = (topic: string) => { submit({ prompt: topic }); }; return (
{isLoading && !object && (
Generating content with citations...
)} {object?.content && (

{object.content.split(/(\[\d+\])/).map((part, index) => { const citationMatch = part.match(/\[(\d+)\]/); if (citationMatch) { const citationNumber = citationMatch[1]; const citation = object.citations?.find( (c: any) => c.number === citationNumber ); if (citation) { return ( {citation.quote && ( {citation.quote} )} ); } } return part; })}

)}
); }; export default CitationDemo; ``` Add the following route to your backend: ```ts title="app/api/citation/route.ts" import { streamObject } from "ai"; import { z } from "zod"; export const citationSchema = z.object({ content: z.string(), citations: z.array( z.object({ number: z.string(), title: z.string(), url: z.string(), description: z.string().optional(), quote: z.string().optional(), }) ), }); // 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: citationSchema, prompt: `Generate a well-researched paragraph about ${prompt} with proper citations. Include: - A comprehensive paragraph with inline citations marked as [1], [2], etc. - 2-3 citations with realistic source information - Each citation should have a title, URL, and optional description/quote - Make the content informative and the sources credible Format citations as numbered references within the text.`, }); return result.toTextStreamResponse(); } ``` ## Features * Hover interaction to reveal detailed citation information * **Carousel navigation** for multiple citations with prev/next controls * **Live index tracking** showing current slide position (e.g., "1/5") * Support for source titles, URLs, and descriptions * Optional quote blocks for relevant excerpts * Composable architecture for flexible citation formats * Accessible design with proper keyboard navigation * Seamless integration with AI-generated content * Clean visual design that doesn't disrupt reading flow * Smart badge display showing source hostname and count ## Usage with AI SDK Currently, there is no official support for inline citations with Streamdown or the Response component. This is because: * There isn't any good markdown syntax for inline citations * Language models don't naturally respond with inline citation syntax * The AI SDK doesn't have built-in support for inline citations ### Potential Approaches While these methods are hypothetical and not officially supported, there are two conceptual ways inline citations could work with Streamdown: 1. **Footnote conversion**: GitHub Flavored Markdown (GFM) handles footnotes using `[^1]` syntax. You could hypothetically remove the default footnote rendering and convert footnotes to inline citations instead. 2. **Custom HTML syntax**: You could add a system prompt instructing the model to use a special HTML syntax like `` and pass that as a custom component to Streamdown. These approaches require custom implementation and are not currently supported out of the box. We will investigate official support for this use case in the future. For now, the recommended approach is to use `experimental_useObject` (as shown in the usage example above) to generate structured citation data, then manually parse and render inline citations. ## Props ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ", }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> --- title: Message description: A comprehensive suite of components for displaying chat messages, including message rendering, branching, actions, and markdown responses. --- # Message The `Message` component suite provides a complete set of tools for building chat interfaces. It includes components for displaying messages from users and AI assistants, managing multiple response branches, adding action buttons, and rendering markdown content. **Important:** After adding the component, you'll need to add the following to your `globals.css` file: ```css @source "../node_modules/streamdown/dist/*.js"; ``` This is **required** for the MessageResponse component to work properly. Without this import, the Streamdown styles will not be applied to your project. See [Streamdown's documentation](https://streamdown.ai/) for more details. ## Installation ## Features * Displays messages from both user and AI assistant with distinct styling and automatic alignment * Minimalist flat design with user messages in secondary background and assistant messages full-width * **Response branching** with navigation controls to switch between multiple AI response versions * **Markdown rendering** with GFM support (tables, task lists, strikethrough), math equations, and smart streaming * **Action buttons** for common operations (retry, like, dislike, copy, share) with tooltips and state management * **File attachments** display with support for images and generic files with preview and remove functionality * Code blocks with syntax highlighting and copy-to-clipboard functionality * Keyboard accessible with proper ARIA labels * Responsive design that adapts to different screen sizes * Seamless light/dark theme integration Branching is an advanced use case you can implement to suit your needs. While the AI SDK does not provide built-in branching support, you have full flexibility to design and manage multiple response paths. ## Usage with AI SDK Build a simple chat UI where the user can copy or regenerate the most recent message. Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { useState } from "react"; import { MessageActions, MessageAction, } from "@/components/ai-elements/message"; import { Message, MessageContent } from "@/components/ai-elements/message"; import { Conversation, ConversationContent, ConversationScrollButton, } from "@/components/ai-elements/conversation"; import { PromptInput, type PromptInputMessage, PromptInputTextarea, PromptInputSubmit, } from "@/components/ai-elements/prompt-input"; import { MessageResponse } from "@/components/ai-elements/message"; import { RefreshCcwIcon, CopyIcon } from "lucide-react"; import { useChat } from "@ai-sdk/react"; import { Fragment } from "react"; const ActionsDemo = () => { const [input, setInput] = useState(""); const { messages, sendMessage, status, regenerate } = useChat(); const handleSubmit = (message: PromptInputMessage) => { if (message.text.trim()) { sendMessage({ text: message.text }); setInput(""); } }; return (
{messages.map((message, messageIndex) => ( {message.parts.map((part, i) => { switch (part.type) { case "text": const isLastMessage = messageIndex === messages.length - 1; return ( {part.text} {message.role === "assistant" && isLastMessage && ( regenerate()} label="Retry" > navigator.clipboard.writeText(part.text) } label="Copy" > )} ); default: return null; } })} ))} setInput(e.currentTarget.value)} className="pr-12" />
); }; export default ActionsDemo; ``` ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` void", }, "...props": { description: "Any other props are spread to the root div.", type: "React.HTMLAttributes", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` A container for placing actions and branch selectors below a message. Lays out children in a horizontal row with space-between alignment. ', }, }} /> ``` ``` --- title: Model Selector description: A searchable command palette for selecting AI models in your chat interface. --- # Model Selector The `ModelSelector` component provides a searchable command palette interface for selecting AI models. It's built on top of the cmdk library and provides a keyboard-navigable interface with search functionality. ## Installation ## Features * Searchable interface with keyboard navigation * Fuzzy search filtering across model names * Grouped model organization by provider * Keyboard shortcuts support * Empty state handling * Customizable styling with Tailwind CSS * Built on cmdk for excellent accessibility * TypeScript support with proper type definitions ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` , "src" | "alt">', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> --- title: Plan description: A collapsible plan component for displaying AI-generated execution plans with streaming support and shimmer animations. --- # Plan 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. ## Installation ## 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 ### `` ", }, }} /> ### `` ", }, }} /> ### `` , "children">', }, }} /> ### `` , "children">', }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ', }, }} /> ### `` ", }, }} /> --- title: Prompt Input description: 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. --- # Prompt Input The `PromptInput` component 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. ## Installation ## Usage with AI SDK Build a fully functional chat app using `PromptInput`, [`Conversation`](/components/conversation) with a model picker: Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { Attachment, AttachmentPreview, AttachmentRemove, Attachments, } from "@/components/ai-elements/attachments"; import { PromptInput, PromptInputActionAddAttachments, PromptInputActionAddScreenshot, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuTrigger, PromptInputBody, PromptInputButton, PromptInputHeader, type PromptInputMessage, PromptInputSelect, PromptInputSelectContent, PromptInputSelectItem, PromptInputSelectTrigger, PromptInputSelectValue, PromptInputSubmit, PromptInputTextarea, PromptInputFooter, PromptInputTools, usePromptInputAttachments, } from "@/components/ai-elements/prompt-input"; import { GlobeIcon } from "lucide-react"; import { useState } from "react"; import { useChat } from "@ai-sdk/react"; import { Conversation, ConversationContent, ConversationScrollButton, } from "@/components/ai-elements/conversation"; import { Message, MessageContent, MessageResponse, } from "@/components/ai-elements/message"; const PromptInputAttachmentsDisplay = () => { const attachments = usePromptInputAttachments(); if (attachments.files.length === 0) { return null; } return ( {attachments.files.map((attachment) => ( attachments.remove(attachment.id)} > ))} ); }; const models = [ { id: "gpt-4o", name: "GPT-4o" }, { id: "claude-opus-4-20250514", name: "Claude 4 Opus" }, ]; const InputDemo = () => { const [text, setText] = useState(""); const [model, setModel] = useState(models[0].id); const [useWebSearch, setUseWebSearch] = useState(false); const { messages, status, sendMessage } = useChat(); const handleSubmit = (message: PromptInputMessage) => { const hasText = Boolean(message.text); const hasAttachments = Boolean(message.files?.length); if (!(hasText || hasAttachments)) { return; } sendMessage( { text: message.text || "Sent with attachments", files: message.files, }, { body: { model: model, webSearch: useWebSearch, }, } ); setText(""); }; return (
{messages.map((message) => ( {message.parts.map((part, i) => { switch (part.type) { case "text": return ( {part.text} ); default: return null; } })} ))} setText(e.target.value)} value={text} /> setUseWebSearch(!useWebSearch)} tooltip={{ content: "Search the web", shortcut: "⌘K" }} variant={useWebSearch ? "default" : "ghost"} > Search { setModel(value); }} value={model} > {models.map((model) => ( {model.name} ))}
); }; export default InputDemo; ``` Add the following route to your backend: ```ts title="app/api/chat/route.ts" import { streamText, UIMessage, convertToModelMessages } from "ai"; // Allow streaming responses up to 30 seconds export const maxDuration = 30; export async function POST(req: Request) { const { model, messages, webSearch, }: { messages: UIMessage[]; model: string; webSearch?: boolean; } = await req.json(); const result = streamText({ model: webSearch ? "perplexity/sonar" : model, messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse(); } ``` ## Features * Auto-resizing textarea that adjusts height based on content * File attachment support with drag-and-drop * Built-in screenshot capture action * Image preview for image attachments * Configurable file constraints (max files, max size, accepted types) * Automatic submit button icons based on status * Support for keyboard shortcuts (Enter to submit, Shift+Enter for new line) * Customizable min/max height for the textarea * Flexible toolbar with support for custom actions and tools * Built-in model selection dropdown * Built-in native speech recognition button (Web Speech API) * Optional provider for lifted state management * Form automatically resets on submit * Responsive design with mobile-friendly controls * Clean, modern styling with customizable themes * Form-based submission handling * Hidden file input sync for native form posts * Global document drop support (opt-in) ## Examples ### Cursor style ### Button tooltips Buttons can display tooltips with optional keyboard shortcut hints. Hover over the buttons below to see the tooltips. ## Props ### `` void", }, accept: { description: 'File types to accept (e.g., "image/*"). Leave undefined for any.', type: "string", }, multiple: { description: "Whether to allow multiple file selection.", type: "boolean", }, globalDrop: { description: "When true, accepts file drops anywhere on the document.", type: "boolean", }, syncHiddenInput: { description: "Render a hidden input with given name for native form posts.", type: "boolean", }, maxFiles: { description: "Maximum number of files allowed.", type: "number", }, maxFileSize: { description: "Maximum file size in bytes.", type: "number", }, onError: { description: "Handler for file validation errors.", type: '(err: { code: "max_files" | "max_file_size" | "accept", message: string }) => void', }, "...props": { description: "Any other props are spread to the root form element.", type: "React.HTMLAttributes", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> #### Tooltip Examples ```tsx // Simple string tooltip // Tooltip with keyboard shortcut hint // Tooltip with custom position ``` ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### Attachments Attachment components have been moved to a separate module. See the [Attachment](/components/attachment) component documentation for details on ``, ``, ``, ``, and ``. ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` Optional global provider that lifts PromptInput state outside of PromptInput. When used, it allows you to access and control the input state from anywhere within the provider tree. If not used, PromptInput stays fully self-managed. ### `` , "align">', }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ## Hooks ### `usePromptInputAttachments` Access and manage file attachments within a PromptInput context. ```tsx const attachments = usePromptInputAttachments(); // Available methods: attachments.files; // Array of current attachments attachments.add(files); // Add new files attachments.remove(id); // Remove an attachment by ID attachments.clear(); // Clear all attachments attachments.openFileDialog(); // Open file selection dialog ``` ### `usePromptInputController` Access the full PromptInput controller from a PromptInputProvider. Only available when using the provider. ```tsx const controller = usePromptInputController(); // Available methods: controller.textInput.value; // Current text input value controller.textInput.setInput(value); // Set text input value controller.textInput.clear(); // Clear text input controller.attachments; // Same as usePromptInputAttachments ``` ### `useProviderAttachments` Access attachments context from a PromptInputProvider. Only available when using the provider. ```tsx const attachments = useProviderAttachments(); // Same interface as usePromptInputAttachments ``` ### `usePromptInputReferencedSources` Access referenced sources context within a PromptInput. ```tsx const sources = usePromptInputReferencedSources(); // Available methods: sources.sources; // Array of current referenced sources sources.add(sources); // Add new source(s) sources.remove(id); // Remove a source by ID sources.clear(); // Clear all sources ``` --- title: Queue description: A comprehensive queue component system for displaying message lists, todos, and collapsible task sections in AI applications. --- # Queue The `Queue` component provides a flexible system for displaying lists of messages, todos, attachments, and collapsible sections. Perfect for showing AI workflow progress, pending tasks, message history, or any structured list of items in your application. ## Installation ## Features * Flexible component system with composable parts * Collapsible sections with smooth animations * Support for completed/pending state indicators * Built-in scroll area for long lists * Attachment display with images and file indicators * Hover-revealed action buttons for queue items * 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 ## Examples ### With PromptInput ## Props ### `` ', }, }} /> ### `` ", }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` , "variant" | "size">', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ## Type Exports ### `QueueMessagePart` Interface for message parts within queue messages. ```tsx interface QueueMessagePart { type: string; text?: string; url?: string; filename?: string; mediaType?: string; } ``` ### `QueueMessage` Interface for queue message items. ```tsx interface QueueMessage { id: string; parts: QueueMessagePart[]; } ``` ### `QueueTodo` Interface for todo items in the queue. ```tsx interface QueueTodo { id: string; title: string; description?: string; status?: "pending" | "completed"; } ``` --- title: Reasoning description: A collapsible component that displays AI reasoning content, automatically opening during streaming and closing when finished. --- # Reasoning The `Reasoning` component displays AI reasoning content, automatically opening during streaming and closing when finished. ## Installation ## Usage with AI SDK Build a chatbot with reasoning using Deepseek R1 or other reasoning models. Some models (like GPT with high reasoning effort) return multiple reasoning parts instead of a single streaming block. The example below consolidates all reasoning parts into a single component to avoid displaying multiple "Thinking..." indicators. Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { Reasoning, ReasoningContent, ReasoningTrigger, } from "@/components/ai-elements/reasoning"; import { Conversation, ConversationContent, ConversationScrollButton, } from "@/components/ai-elements/conversation"; import { PromptInput, type PromptInputMessage, PromptInputTextarea, PromptInputSubmit, } from "@/components/ai-elements/prompt-input"; import { Spinner } from "@/components/ui/spinner"; import { Message, MessageContent, MessageResponse, } from "@/components/ai-elements/message"; import { useState } from "react"; import { useChat } from "@ai-sdk/react"; import type { UIMessage } from "ai"; const MessageParts = ({ message, isLastMessage, isStreaming, }: { message: UIMessage; isLastMessage: boolean; isStreaming: boolean; }) => { // Consolidate all reasoning parts into one block const reasoningParts = message.parts.filter( (part) => part.type === "reasoning" ); const reasoningText = reasoningParts.map((part) => part.text).join("\n\n"); const hasReasoning = reasoningParts.length > 0; // Check if reasoning is still streaming (last part is reasoning on last message) const lastPart = message.parts.at(-1); const isReasoningStreaming = isLastMessage && isStreaming && lastPart?.type === "reasoning"; return ( <> {hasReasoning && ( {reasoningText} )} {message.parts.map((part, i) => { if (part.type === "text") { return ( {part.text} ); } return null; })} ); }; const ReasoningDemo = () => { const [input, setInput] = useState(""); const { messages, sendMessage, status } = useChat(); const handleSubmit = (message: PromptInputMessage) => { sendMessage({ text: message.text }); setInput(""); }; const isStreaming = status === "streaming"; return (
{messages.map((message, index) => ( ))} {status === "submitted" && } setInput(e.currentTarget.value)} className="pr-12" />
); }; export default ReasoningDemo; ``` Add the following route to your backend: ```ts title="app/api/chat/route.ts" import { streamText, UIMessage, convertToModelMessages } from "ai"; // Allow streaming responses up to 30 seconds export const maxDuration = 30; export async function POST(req: Request) { const { model, messages }: { messages: UIMessage[]; model: string } = await req.json(); const result = streamText({ model: "deepseek/deepseek-r1", messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse({ sendReasoning: true, }); } ``` ## Reasoning vs Chain of Thought Use the `Reasoning` component when your model outputs thinking content as a single block or continuous stream (Deepseek R1, Claude with extended thinking, etc.). If your model outputs discrete, labeled steps (search queries, tool calls, distinct thought stages), consider using the [Chain of Thought](/components/chain-of-thought) component instead for a more structured visual representation. ## Features * Automatically opens when streaming content and closes when finished * Manual toggle control for user interaction * Smooth animations and transitions powered by Radix UI * Visual streaming indicator with pulsing animation * Composable architecture with separate trigger and content components * Built with accessibility in mind including keyboard navigation * Responsive design that works across different screen sizes * Seamlessly integrates with both light and dark themes * Built on top of shadcn/ui Collapsible primitives * TypeScript support with proper type definitions ## Props ### `` void", }, duration: { description: "Duration in seconds to display (can be controlled externally).", type: "number", }, "...props": { description: "Any other props are spread to the underlying Collapsible component.", type: "React.ComponentProps", }, }} /> ### `` ReactNode", }, "...props": { description: "Any other props are spread to the underlying CollapsibleTrigger component.", type: "React.ComponentProps", }, }} /> ### `` ", }, }} /> ## Hooks ### `useReasoning` Access the reasoning context from child components. ```tsx const { isStreaming, isOpen, setIsOpen, duration } = useReasoning(); ``` Returns: void", }, duration: { description: "Duration in seconds (undefined while streaming).", type: "number | undefined", }, }} /> --- title: Shimmer description: An animated text shimmer component for creating eye-catching loading states and progressive reveal effects. --- # Shimmer The `Shimmer` component provides an animated shimmer effect that sweeps across text, perfect for indicating loading states, progressive reveals, or drawing attention to dynamic content in AI applications. ## Installation ## Features * Smooth animated shimmer effect using CSS gradients and Framer Motion * Customizable animation duration and spread * Polymorphic component - render as any HTML element via the `as` prop * Automatic spread calculation based on text length * Theme-aware styling using CSS custom properties * Infinite looping animation with linear easing * TypeScript support with proper type definitions * Memoized for optimal performance * Responsive and accessible design * Uses `text-transparent` with background-clip for crisp text rendering ## Examples ### Different Durations ### Custom Elements ## Props ### `` --- title: Sources description: A component that allows a user to view the sources or citations used to generate a response. --- # Sources The `Sources` component allows a user to view the sources or citations used to generate a response. ## Installation ## Usage with AI SDK Build a simple web search agent with Perplexity Sonar. Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { useChat } from "@ai-sdk/react"; import { Source, Sources, SourcesContent, SourcesTrigger, } from "@/components/ai-elements/sources"; import { PromptInput, type PromptInputMessage, PromptInputTextarea, PromptInputSubmit, } from "@/components/ai-elements/prompt-input"; import { Conversation, ConversationContent, ConversationScrollButton, } from "@/components/ai-elements/conversation"; import { Message, MessageContent, MessageResponse, } from "@/components/ai-elements/message"; import { useState } from "react"; import { DefaultChatTransport } from "ai"; const SourceDemo = () => { const [input, setInput] = useState(""); const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: "/api/sources", }), }); const handleSubmit = (message: PromptInputMessage) => { if (message.text.trim()) { sendMessage({ text: message.text }); setInput(""); } }; return (
{messages.map((message) => (
{message.role === "assistant" && ( part.type === "source-url" ).length } /> {message.parts.map((part, i) => { switch (part.type) { case "source-url": return ( ); } })} )} {message.parts.map((part, i) => { switch (part.type) { case "text": return ( {part.text} ); default: return null; } })}
))}
setInput(e.currentTarget.value)} className="pr-12" />
); }; export default SourceDemo; ``` Add the following route to your backend: ```tsx title="api/chat/route.ts" import { convertToModelMessages, streamText, UIMessage } from "ai"; import { perplexity } from "@ai-sdk/perplexity"; // Allow streaming responses up to 30 seconds export const maxDuration = 30; export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } = await req.json(); const result = streamText({ model: "perplexity/sonar", system: "You are a helpful assistant. Keep your responses short (< 100 words) unless you are asked for more details. ALWAYS USE SEARCH.", messages: await convertToModelMessages(messages), }); return result.toUIMessageStreamResponse({ sendSources: true, }); } ``` ## Features * Collapsible component that allows a user to view the sources or citations used to generate a response * Customizable trigger and content components * Support for custom sources or citations * Responsive design with mobile-friendly controls * Clean, modern styling with customizable themes ## Examples ### Custom rendering ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> --- title: Suggestion description: A suggestion component that displays a horizontal row of clickable suggestions for user interaction. --- # Suggestion The `Suggestion` component displays a horizontal row of clickable suggestions for user interaction. ## Installation ## Usage with AI SDK Build a simple input with suggestions users can click to send a message to the LLM. Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { PromptInput, type PromptInputMessage, PromptInputTextarea, PromptInputSubmit, } from "@/components/ai-elements/prompt-input"; import { Suggestion, Suggestions } from "@/components/ai-elements/suggestion"; import { useState } from "react"; import { useChat } from "@ai-sdk/react"; const suggestions = [ "Can you explain how to play tennis?", "What is the weather in Tokyo?", "How do I make a really good fish taco?", ]; const SuggestionDemo = () => { const [input, setInput] = useState(""); const { sendMessage, status } = useChat(); const handleSubmit = (message: PromptInputMessage) => { if (message.text.trim()) { sendMessage({ text: message.text }); setInput(""); } }; const handleSuggestionClick = (suggestion: string) => { sendMessage({ text: suggestion }); }; return (
{suggestions.map((suggestion) => ( ))} setInput(e.currentTarget.value)} className="pr-12" />
); }; export default SuggestionDemo; ``` ## Features * Horizontal row of clickable suggestion buttons * Customizable styling with variant and size options * Flexible layout that wraps suggestions on smaller screens * onClick callback that emits the selected suggestion string * Support for both individual suggestions and suggestion lists * Clean, modern styling with hover effects * Responsive design with mobile-friendly touch targets * TypeScript support with proper type definitions ## Examples ### Usage with AI Input ## Props ### `` ", }, }} /> ### `` void", }, "...props": { description: "Any other props are spread to the underlying shadcn/ui Button component.", type: 'Omit, "onClick">', }, }} /> --- title: Task description: A collapsible task list component for displaying AI workflow progress, with status indicators and optional descriptions. --- # Task 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. ## Installation ## Usage with AI SDK Build a mock async programming agent using [`experimental_generateObject`](/docs/reference/ai-sdk-ui/use-object). Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { experimental_useObject as useObject } from "@ai-sdk/react"; import { Task, TaskItem, TaskItemFile, TaskTrigger, TaskContent, } from "@/components/ai-elements/task"; import { Button } from "@/components/ui/button"; import { tasksSchema } from "@/app/api/task/route"; import { SiReact, SiTypescript, SiJavascript, SiCss, SiHtml5, SiJson, SiMarkdown, } 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 ( {item.text} {item.file.name} ); } } return item?.text || ""; }; return (
{isLoading && !object && (
Generating tasks...
)} {object?.tasks?.map((task: any, taskIndex: number) => ( {task.items?.map((item: any, itemIndex: number) => ( {renderTaskItem(item, itemIndex)} ))} ))}
); }; export default TaskDemo; ``` Add the following route to your backend: ```ts title="app/api/agent.ts" 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 ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> --- title: Tool description: A collapsible component for displaying tool invocation details in AI chatbot interfaces. --- # Tool The `Tool` component displays a collapsible interface for showing/hiding tool details. It is designed to take the `ToolUIPart` type from the AI SDK and display it in a collapsible interface. ## Installation ## Usage in AI SDK Build a simple stateful weather app that renders the last message in a tool using [`useChat`](/docs/reference/ai-sdk-ui/use-chat). Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { useChat } from "@ai-sdk/react"; import { DefaultChatTransport, type ToolUIPart } from "ai"; import { Button } from "@/components/ui/button"; import { MessageResponse } from "@/components/ai-elements/message"; import { Tool, ToolContent, ToolHeader, ToolInput, ToolOutput, } from "@/components/ai-elements/tool"; type WeatherToolInput = { location: string; units: "celsius" | "fahrenheit"; }; type WeatherToolOutput = { location: string; temperature: string; conditions: string; humidity: string; windSpeed: string; lastUpdated: string; }; type WeatherToolUIPart = ToolUIPart<{ fetch_weather_data: { input: WeatherToolInput; output: WeatherToolOutput; }; }>; const Example = () => { const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: "/api/weather", }), }); const handleWeatherClick = () => { sendMessage({ text: "Get weather data for San Francisco in fahrenheit" }); }; const latestMessage = messages[messages.length - 1]; const weatherTool = latestMessage?.parts?.find( (part) => part.type === "tool-fetch_weather_data" ) as WeatherToolUIPart | undefined; return (
{weatherTool && ( {formatWeatherResult(weatherTool.output)} } errorText={weatherTool.errorText} /> )}
); }; function formatWeatherResult(result: WeatherToolOutput): string { return `**Weather for ${result.location}** **Temperature:** ${result.temperature} **Conditions:** ${result.conditions} **Humidity:** ${result.humidity} **Wind Speed:** ${result.windSpeed} *Last updated: ${result.lastUpdated}*`; } export default Example; ``` Add the following route to your backend: ```ts title="app/api/weather/route.tsx" import { streamText, UIMessage, convertToModelMessages } from "ai"; import { z } from "zod"; // Allow streaming responses up to 30 seconds export const maxDuration = 30; export async function POST(req: Request) { const { messages }: { messages: UIMessage[] } = await req.json(); const result = streamText({ model: "openai/gpt-4o", messages: await convertToModelMessages(messages), tools: { fetch_weather_data: { description: "Fetch weather information for a specific location", parameters: z.object({ location: z .string() .describe("The city or location to get weather for"), units: z .enum(["celsius", "fahrenheit"]) .default("celsius") .describe("Temperature units"), }), inputSchema: z.object({ location: z.string(), units: z.enum(["celsius", "fahrenheit"]).default("celsius"), }), execute: async ({ location, units }) => { await new Promise((resolve) => setTimeout(resolve, 1500)); const temp = units === "celsius" ? Math.floor(Math.random() * 35) + 5 : Math.floor(Math.random() * 63) + 41; return { location, temperature: `${temp}°${units === "celsius" ? "C" : "F"}`, conditions: "Sunny", humidity: `12%`, windSpeed: `35 ${units === "celsius" ? "km/h" : "mph"}`, lastUpdated: new Date().toLocaleString(), }; }, }, }, }); return result.toUIMessageStreamResponse(); } ``` ## Features * Collapsible interface for showing/hiding tool details * Visual status indicators with icons and badges * Support for multiple tool execution states (pending, running, completed, error) * Formatted parameter display with JSON syntax highlighting * Result and error handling with appropriate styling * Composable structure for flexible layouts * Accessible keyboard navigation and screen reader support * Consistent styling that matches your design system * Auto-opens completed tools by default for better UX ## Examples ### Input Streaming (Pending) Shows a tool in its initial state while parameters are being processed. ### Input Available (Running) Shows a tool that's actively executing with its parameters. ### Output Available (Completed) Shows a completed tool with successful results. Opens by default to show the results. In this instance, the output is a JSON object, so we can use the `CodeBlock` component to display it. ### Output Error Shows a tool that encountered an error during execution. Opens by default to display the error. ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ## Type Exports ### `ToolPart` Union type representing both static and dynamic tool UI parts. ```tsx type ToolPart = ToolUIPart | DynamicToolUIPart; ``` ## Utilities ### `getStatusBadge` Returns a Badge component with icon and label based on tool state. ```tsx import { getStatusBadge } from "@/components/ai-elements/tool"; // Returns a Badge with appropriate icon and label const badge = getStatusBadge("output-available"); ``` Supported states: * `input-streaming` - "Pending" * `input-available` - "Running" * `approval-requested` - "Awaiting Approval" * `approval-responded` - "Responded" * `output-available` - "Completed" * `output-error` - "Error" * `output-denied` - "Denied" --- title: Agent description: A composable component for displaying AI agent configuration with model, instructions, tools, and output schema. --- # Agent The `Agent` component displays an interface for showing AI agent configuration details. It's designed to represent a configured agent from the AI SDK, showing the agent's model, system instructions, available tools (with expandable input schemas), and output schema. ## Installation ## Usage with AI SDK Display an agent's configuration alongside your chat interface. Tools are displayed in an accordion where clicking the description expands to show the input schema. ```tsx title="app/page.tsx" "use client"; import { tool } from "ai"; import { z } from "zod"; import { Agent, AgentContent, AgentHeader, AgentInstructions, AgentOutput, AgentTool, AgentTools, } from "@/components/ai-elements/agent"; const webSearch = tool({ description: "Search the web for information", inputSchema: z.object({ query: z.string().describe("The search query"), }), }); const readUrl = tool({ description: "Read and parse content from a URL", inputSchema: z.object({ url: z.string().url().describe("The URL to read"), }), }); const outputSchema = `z.object({ sentiment: z.enum(['positive', 'negative', 'neutral']), score: z.number(), summary: z.string(), })`; export default function Page() { return ( Analyze the sentiment of the provided text and return a structured analysis with sentiment classification, confidence score, and summary. ); } ``` ## Features * Model badge in header * Instructions rendered as markdown * Tools displayed as accordion items with expandable input schemas * Output schema display with syntax highlighting * Composable structure for flexible layouts * Works with AI SDK `Tool` type ## Props ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ', }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ', }, }} /> --- title: Artifact description: A container component for displaying generated content like code, documents, or other outputs with built-in actions. --- # Artifact The `Artifact` component provides a structured container for displaying generated content like code, documents, or other outputs with built-in header actions. ## Installation ## Features * Structured container with header and content areas * Built-in header with title and description support * Flexible action buttons with tooltips * Customizable styling for all subcomponents * Support for close buttons and action groups * Clean, modern design with border and shadow * Responsive layout that adapts to content * TypeScript support with proper type definitions * Composable architecture for maximum flexibility ## Examples ### With Code Display ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> --- title: Code Block description: Provides syntax highlighting, line numbers, and copy to clipboard functionality for code blocks. --- # Code Block The `CodeBlock` component provides syntax highlighting, line numbers, and copy to clipboard functionality for code blocks. It's fully composable, allowing you to customize the header, actions, and content. ## Installation ## Usage The CodeBlock is fully composable. Here's a basic example: ```tsx import { CodeBlock, CodeBlockActions, CodeBlockCopyButton, CodeBlockFilename, CodeBlockHeader, CodeBlockTitle, } from "@/components/ai-elements/code-block"; import { FileIcon } from "lucide-react"; export const Example = () => ( example.ts ); ``` ## Features * Syntax highlighting with Shiki * Line numbers (optional) * Copy to clipboard functionality * Automatic light/dark theme switching via CSS variables * Language selector for multi-language examples * Fully composable architecture * Accessible design ## Examples ### Dark Mode To use the `CodeBlock` component in dark mode, wrap it in a `div` with the `dark` class. ### Language Selector Add a language selector to switch between different code implementations: ## Props ### `` ### `` Container for the header row. Uses flexbox with `justify-between`. ### `` Left-aligned container for icon and filename. Uses flexbox with `gap-2`. ### `` Displays the filename in monospace font. ### `` Right-aligned container for action buttons. Uses flexbox with `gap-2`. ### `` void", }, onError: { description: "Callback fired if copying fails.", type: "(error: Error) => void", }, timeout: { description: "How long to show the copied state (ms).", type: "number", default: "2000", }, children: { description: "Custom content for the button. Defaults to copy/check icons.", type: "React.ReactNode", }, className: { description: "Additional CSS classes.", type: "string", }, }} /> ### `` Wrapper for the language selector. Extends shadcn/ui Select. void", }, children: { description: "Selector components (Trigger, Content, Items).", type: "React.ReactNode", }, }} /> ### `` Trigger button for the language selector dropdown. Pre-styled for code block header. ### `` Displays the selected language value. ### `` Dropdown content container. Defaults to `align="end"`. ### `` Individual language option in the dropdown. ### `` Low-level container component with performance optimizations (`contentVisibility`). Used internally by CodeBlock. ### `` Low-level component that handles syntax highlighting. Used internally by CodeBlock, but can be used directly for custom layouts. --- title: Commit description: Display commit information with hash, message, author, and file changes. --- # Commit The `Commit` component displays commit details including hash, message, author, timestamp, and changed files. ## Installation ## Features * Commit hash display with copy button * Author avatar with initials * Relative timestamp formatting * Collapsible file changes list * Color-coded file status (added/modified/deleted/renamed) * Line additions/deletions count ## File Status | Status | Label | Color | | ---------- | ----- | ------ | | `added` | A | Green | | `modified` | M | Yellow | | `deleted` | D | Red | | `renamed` | R | Blue | ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` void", }, onError: { description: "Callback if copying fails.", type: "(error: Error) => void", }, timeout: { description: "Duration to show copied state (ms).", type: "number", default: "2000", }, "...props": { description: "Spread to the Button component.", type: "React.ComponentProps", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> --- title: Environment Variables description: Display environment variables with masking and copy functionality. --- # Environment Variables The `EnvironmentVariables` component displays environment variables with value masking, visibility toggle, and copy functionality. ## Installation ## Features * Value masking by default * Toggle visibility switch * Copy individual values * Export format support (`export KEY="value"`) * Required badge indicator ## Props ### `` void", }, "...props": { description: "Spread to the container div.", type: "React.HTMLAttributes", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` void", }, onError: { description: "Callback if copying fails.", type: "(error: Error) => void", }, timeout: { description: "Duration to show copied state (ms).", type: "number", default: "2000", }, "...props": { description: "Spread to the Button component.", type: "React.ComponentProps", }, }} /> ### `` ", }, }} /> --- title: File Tree description: Display hierarchical file and folder structure with expand/collapse functionality. --- # File Tree The `FileTree` component displays a hierarchical file system structure with expandable folders and file selection. ## Installation ## Features * Hierarchical folder structure * Expand/collapse folders * File selection with callback * Keyboard accessible * Customizable icons * Controlled and uncontrolled modes ## Examples ### Basic Usage ### With Selection ### Default Expanded ## Props ### `` ", }, defaultExpanded: { description: "Default expanded paths.", type: "Set", default: "new Set()", }, selectedPath: { description: "Currently selected file/folder path.", type: "string", }, onSelect: { description: "Callback when a file/folder is selected.", type: "(path: string) => void", }, onExpandedChange: { description: "Callback when expanded paths change.", type: "(expanded: Set) => void", }, className: { description: "Additional CSS classes.", type: "string", }, }} /> ### `` ### `` ### Subcomponents * `FileTreeIcon` - Icon wrapper * `FileTreeName` - Name text * `FileTreeActions` - Action buttons container (stops click propagation) --- title: JSX Preview description: A component that dynamically renders JSX strings with streaming support for AI-generated UI. --- # JSX Preview The `JSXPreview` component renders JSX strings dynamically, supporting streaming scenarios where JSX may be incomplete. It automatically closes unclosed tags during streaming, making it ideal for displaying AI-generated UI components in real-time. ## Installation ## Features * Renders JSX strings dynamically using `react-jsx-parser` * Streaming support with automatic tag completion * Custom component injection for rendering your own components * Error handling with customizable error display * Context-based architecture for flexible composition ## Usage with AI SDK The JSXPreview component integrates with the AI SDK to render generated UI in real-time: ```tsx title="components/generated-ui.tsx" "use client"; import { JSXPreview, JSXPreviewContent, JSXPreviewError, } from "@/components/ai-elements/jsx-preview"; type GeneratedUIProps = { jsx: string; isStreaming: boolean; }; export const GeneratedUI = ({ jsx, isStreaming }: GeneratedUIProps) => ( console.error("JSX Parse Error:", error)} > ); ``` ### With Custom Components You can inject custom components to be used within the rendered JSX: ```tsx title="components/generated-ui-with-components.tsx" "use client"; import { JSXPreview, JSXPreviewContent, } from "@/components/ai-elements/jsx-preview"; import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; const customComponents = { Button, Card, }; export const GeneratedUIWithComponents = ({ jsx }: { jsx: string }) => ( ); ``` ## Props ### `` ", }, bindings: { description: "Variables and functions available within the JSX scope.", type: "Record", }, onError: { description: "Callback fired when a parsing or rendering error occurs.", type: "(error: Error) => void", }, "...props": { description: "Any other props are spread to the underlying div element.", type: "React.ComponentProps<'div'>", }, }} /> ### `` ", }, }} /> ### `` ReactNode)", }, "...props": { description: "Any other props are spread to the underlying div element.", type: "React.ComponentProps<'div'>", }, }} /> --- title: Package Info description: Display dependency information and version changes. --- # Package Info The `PackageInfo` component displays package dependency information including version changes and change type badges. ## Installation ## Features * Version change display (current → new) * Color-coded change type badges * Dependencies list * Description support ## Change Types | Type | Color | Use Case | | --------- | ------ | ------------------ | | `major` | Red | Breaking changes | | `minor` | Yellow | New features | | `patch` | Green | Bug fixes | | `added` | Blue | New dependency | | `removed` | Gray | Removed dependency | ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> --- title: Sandbox description: A collapsible container for displaying AI-generated code and output in chat interfaces. --- # Sandbox The `Sandbox` component provides a structured way to display AI-generated code alongside its execution output in chat conversations. It features a collapsible container with status indicators and tabbed navigation between code and output views. It's designed to be used with `CodeBlock` for displaying code and `StackTrace` for displaying errors. ## Installation ## Features * Collapsible container with smooth animations * Status badges showing execution state (Pending, Running, Completed, Error) * Tabs for Code and Output views * Syntax-highlighted code display * Copy button for easy code sharing * Works with AI SDK tool state patterns ## Usage with AI SDK The Sandbox component integrates with the AI SDK's tool state to show code generation progress: ```tsx title="components/code-sandbox.tsx" "use client"; import type { ToolUIPart } from "ai"; import { Sandbox, SandboxContent, SandboxHeader, SandboxTabContent, SandboxTabs, SandboxTabsBar, SandboxTabsList, SandboxTabsTrigger, } from "@/components/ai-elements/sandbox"; import { CodeBlock } from "@/components/ai-elements/code-block"; type CodeSandboxProps = { toolPart: ToolUIPart; }; export const CodeSandbox = ({ toolPart }: CodeSandboxProps) => { const code = toolPart.input?.code ?? ""; const output = toolPart.output?.logs ?? ""; return ( Code Output ); }; ``` ## Props ### `` ", }, }} /> ### `` ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> --- title: Schema Display description: Display REST API endpoint documentation with parameters, request/response bodies. --- # Schema Display The `SchemaDisplay` component visualizes REST API endpoints with HTTP methods, paths, parameters, and request/response schemas. ## Installation ## Features * Color-coded HTTP methods * Path parameter highlighting * Collapsible parameters section * Request/response body schemas * Nested object property display * Required field indicators ## Method Colors | Method | Color | | -------- | ------ | | `GET` | Green | | `POST` | Blue | | `PUT` | Orange | | `PATCH` | Yellow | | `DELETE` | Red | ## Examples ### Basic Usage ### With Parameters ### With Request/Response Bodies ### Nested Properties ## Props ### `` ### `SchemaParameter` ```tsx interface SchemaParameter { name: string; type: string; required?: boolean; description?: string; location?: "path" | "query" | "header"; } ``` ### `SchemaProperty` ```tsx interface SchemaProperty { name: string; type: string; required?: boolean; description?: string; properties?: SchemaProperty[]; // For objects items?: SchemaProperty; // For arrays } ``` ### Subcomponents * `SchemaDisplayHeader` - Header container * `SchemaDisplayMethod` - Color-coded method badge * `SchemaDisplayPath` - Path with highlighted parameters * `SchemaDisplayDescription` - Description text * `SchemaDisplayContent` - Content container * `SchemaDisplayParameters` - Collapsible parameters section * `SchemaDisplayParameter` - Individual parameter * `SchemaDisplayRequest` - Collapsible request body * `SchemaDisplayResponse` - Collapsible response body * `SchemaDisplayProperty` - Schema property (recursive) * `SchemaDisplayExample` - Code example block --- title: Snippet description: Lightweight inline code display for terminal commands and short code references. --- # Snippet The `Snippet` component provides a lightweight way to display terminal commands and short code snippets with copy functionality. Built on top of InputGroup, it's designed for brief code references in text. ## Installation ## Features * Composable architecture with InputGroup * Optional prefix text (e.g., `$` for terminal commands) * Built-in copy button * Compact design for chat/markdown ## Examples ### Without Prefix ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` , "readOnly" | "value">', }, }} /> ### `` void", }, onError: { description: "Callback fired if copying fails.", type: "(error: Error) => void", }, timeout: { description: "How long to show the copied state (ms).", type: "number", default: "2000", }, children: { description: "Custom button content.", type: "React.ReactNode", }, "...props": { description: "Spread to the InputGroupButton component.", type: "React.ComponentProps", }, }} /> --- title: Stack Trace description: Displays formatted JavaScript/Node.js error stack traces with syntax highlighting and collapsible frames. --- # Stack Trace The `StackTrace` component displays formatted JavaScript/Node.js error stack traces with clickable file paths, internal frame dimming, and collapsible content. ## Installation ## Usage with AI SDK Build an error display tool that shows stack traces from AI-generated code using the [`useChat`](https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat) hook. Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { useChat } from "@ai-sdk/react"; import { StackTrace, StackTraceHeader, StackTraceError, StackTraceErrorType, StackTraceErrorMessage, StackTraceActions, StackTraceCopyButton, StackTraceExpandButton, StackTraceContent, StackTraceFrames, } from "@/components/ai-elements/stack-trace"; export default function Page() { const { messages } = useChat({ api: "/api/run-code", }); return (
{messages.map((message) => { const toolInvocations = message.parts?.filter( (part) => part.type === "tool-invocation" ); return toolInvocations?.map((tool) => { if (tool.toolName === "runCode" && tool.result?.error) { return ( ); } return null; }); })}
); } ``` Add the following route to your backend: ```tsx title="api/run-code/route.ts" import { streamText, tool } from "ai"; import { z } from "zod"; export async function POST(req: Request) { const { messages } = await req.json(); const result = streamText({ model: "openai/gpt-4o", messages, tools: { runCode: tool({ description: "Execute JavaScript code and return any errors", parameters: z.object({ code: z.string(), }), execute: async ({ code }) => { try { // Execute code in sandbox eval(code); return { success: true }; } catch (error) { return { error: (error as Error).stack }; } }, }), }, }); return result.toDataStreamResponse(); } ``` ## Features * Parses standard JavaScript/Node.js stack trace format * Highlights error type in red * Dims internal frames (node\_modules, node: paths) * Collapsible content with smooth animation * Copy full stack trace to clipboard * Clickable file paths with line/column numbers ## Examples ### Collapsed by Default ### Hide Internal Frames ## Props ### `` void", }, onFilePathClick: { description: "Callback when a file path is clicked. Receives the file path, line number, and column number.", type: "(path: string, line?: number, column?: number) => void", }, children: { description: "Child elements (StackTraceHeader, StackTraceContent, etc.).", type: "React.ReactNode", }, className: { description: "Additional CSS classes.", type: "string", }, "...props": { description: "Any other props are spread to the root div.", type: "React.HTMLAttributes", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` void", }, onError: { description: "Callback fired if copying fails.", type: "(error: Error) => void", }, timeout: { description: "How long to show the copied state (ms).", type: "number", default: "2000", }, children: { description: "Custom content for the button. Defaults to copy/check icons.", type: "React.ReactNode", }, className: { description: "Additional CSS classes.", type: "string", }, "...props": { description: "Any other props are spread to the underlying shadcn/ui Button component.", type: "React.ComponentProps", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> --- title: Terminal description: Display streaming console output with full ANSI color support. --- # Terminal The `Terminal` component displays console output with ANSI color support, streaming indicators, and auto-scroll functionality. ## Installation ## Features * Full ANSI color support (256 colors, bold, italic, underline) * Streaming mode with cursor animation * Auto-scroll to latest output * Copy output to clipboard * Clear button support * Dark terminal theme ## ANSI Support The Terminal uses `ansi-to-react` to parse ANSI escape codes: ```bash \x1b[32m✓\x1b[0m Success # Green checkmark \x1b[31m✗\x1b[0m Error # Red X \x1b[33mwarn\x1b[0m Warning # Yellow text \x1b[1mBold\x1b[0m # Bold text ``` ## Examples ### Basic Usage ### Streaming Mode ### With Clear Button ## Props ### `` void", }, className: { description: "Additional CSS classes.", type: "string", }, }} /> ### `` void", }, onError: { description: "Callback if copying fails.", type: "(error: Error) => void", }, timeout: { description: "Duration to show copied state (ms).", type: "number", default: "2000", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> --- title: Test Results description: Display test suite results with pass/fail/skip status and error details. --- # Test Results The `TestResults` component displays test suite results including summary statistics, progress, individual tests, and error details. ## Installation ## Features * Summary statistics (passed/failed/skipped) * Progress bar visualization * Collapsible test suites * Individual test status and duration * Error messages with stack traces * Color-coded status indicators ## Status Colors | Status | Color | Use Case | | --------- | --------------- | ---------------- | | `passed` | Green | Test succeeded | | `failed` | Red | Test failed | | `skipped` | Yellow | Test skipped | | `running` | Blue (animated) | Test in progress | ## Examples ### Basic Usage ### With Test Suites ### With Error Details ## Props ### `` ### `` ### `` ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> --- title: Web Preview description: A composable component for previewing the result of a generated UI, with support for live examples and code display. --- # Web Preview The `WebPreview` component provides a flexible way to showcase the result of a generated UI component, along with its source code. It is designed for documentation and demo purposes, allowing users to interact with live examples and view the underlying implementation. ## Installation ## Usage with AI SDK Build a simple v0 clone using the [v0 Platform API](https://v0.dev/docs/api/platform). Install the `v0-sdk` package: npm pnpm yarn bun ```bash npm i v0-sdk ``` ```bash pnpm add v0-sdk ``` ```bash yarn add v0-sdk ``` ```bash bun add v0-sdk ``` Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { WebPreview, WebPreviewBody, WebPreviewNavigation, WebPreviewUrl, } from "@/components/ai-elements/web-preview"; import { useState } from "react"; import { PromptInput, type PromptInputMessage, PromptInputTextarea, PromptInputSubmit, } from "@/components/ai-elements/prompt-input"; import { Spinner } from "@/components/ui/spinner"; const WebPreviewDemo = () => { const [previewUrl, setPreviewUrl] = useState(""); const [prompt, setPrompt] = useState(""); const [isGenerating, setIsGenerating] = useState(false); const handleSubmit = async (message: PromptInputMessage) => { if (!message.text.trim()) return; setPrompt(""); setIsGenerating(true); try { const response = await fetch("/api/v0", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ prompt: message.text }), }); const data = await response.json(); setPreviewUrl(data.demo || "/"); console.log("Generation finished:", data); } catch (error) { console.error("Generation failed:", error); } finally { setIsGenerating(false); } }; return (
{isGenerating ? (

Generating app, this may take a few seconds...

) : previewUrl ? ( ) : (
Your generated app will appear here
)}
setPrompt(e.currentTarget.value)} className="pr-12 min-h-[60px]" />
); }; export default WebPreviewDemo; ``` Add the following route to your backend: ```ts title="app/api/v0/route.ts" import { v0 } from "v0-sdk"; export async function POST(req: Request) { const { prompt }: { prompt: string } = await req.json(); const result = await v0.chats.create({ system: "You are an expert coder", message: prompt, modelConfiguration: { modelId: "v0-1.5-sm", imageGenerations: false, thinking: false, }, }); return Response.json({ demo: result.demo, webUrl: result.webUrl, }); } ``` ## Features * Live preview of UI components * Composable architecture with dedicated sub-components * Responsive design modes (Desktop, Tablet, Mobile) * Navigation controls with back/forward functionality * URL input and example selector * Full screen mode support * Console logging with timestamps * Context-based state management * Consistent styling with the design system * Easy integration into documentation pages ## Props ### `` void", }, "...props": { description: "Any other props are spread to the root div.", type: "React.HTMLAttributes", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ', }, "...props": { description: "Any other props are spread to the root div.", type: "React.HTMLAttributes", }, }} /> --- title: Image description: Displays AI-generated images from the AI SDK. --- # Image The `Image` component displays AI-generated images from the AI SDK. It accepts a [`Experimental_GeneratedImage`](/docs/reference/ai-sdk-core/generate-image) object from the AI SDK's `generateImage` function and automatically renders it as an image. ## Installation ## Usage with AI SDK Build a simple app allowing a user to generate an image given a prompt. Install the `@ai-sdk/openai` package: npm pnpm yarn bun ```bash npm i @ai-sdk/openai ``` ```bash pnpm add @ai-sdk/openai ``` ```bash yarn add @ai-sdk/openai ``` ```bash bun add @ai-sdk/openai ``` Add the following component to your frontend: ```tsx title="app/page.tsx" "use client"; import { Image } from "@/components/ai-elements/image"; import { PromptInput, type PromptInputMessage, PromptInputTextarea, PromptInputSubmit, } from "@/components/ai-elements/prompt-input"; import { useState } from "react"; import { Spinner } from "@/components/ui/spinner"; const ImageDemo = () => { const [prompt, setPrompt] = useState("A futuristic cityscape at sunset"); const [imageData, setImageData] = useState(null); const [isLoading, setIsLoading] = useState(false); const handleSubmit = async (message: PromptInputMessage) => { if (!message.text.trim()) return; setPrompt(""); setIsLoading(true); try { const response = await fetch("/api/image", { method: "POST", body: JSON.stringify({ prompt: message.text.trim() }), }); const data = await response.json(); setImageData(data); } catch (error) { console.error("Error generating image:", error); } finally { setIsLoading(false); } }; return (
{imageData && (
Generated image
)} {isLoading && }
setPrompt(e.currentTarget.value)} className="pr-12" />
); }; export default ImageDemo; ``` Add the following route to your backend: ```ts title="app/api/image/route.ts" import { openai } from "@ai-sdk/openai"; import { experimental_generateImage } from "ai"; export async function POST(req: Request) { const { prompt }: { prompt: string } = await req.json(); const { image } = await experimental_generateImage({ model: openai.image("dall-e-3"), prompt: prompt, size: "1024x1024", }); return Response.json({ base64: image.base64, uint8Array: image.uint8Array, mediaType: image.mediaType, }); } ``` ## Features * Accepts `Experimental_GeneratedImage` objects directly from the AI SDK * Automatically creates proper data URLs from base64-encoded image data * Supports all standard HTML image attributes * Responsive by default with `max-w-full h-auto` styling * Customizable with additional CSS classes * Includes proper TypeScript types for AI SDK compatibility ## Props ### `` --- title: Open In Chat description: A dropdown menu for opening queries in various AI chat platforms including ChatGPT, Claude, T3, Scira, and v0. --- # Open In Chat The `OpenIn` component provides a dropdown menu that allows users to open queries in different AI chat platforms with a single click. ## Installation ## Features * Pre-configured links to popular AI chat platforms * Context-based query passing for cleaner API * Customizable dropdown trigger button * Automatic URL parameter encoding for queries * Support for ChatGPT, Claude, T3 Chat, Scira AI, v0, and Cursor * Branded icons for each platform * TypeScript support with proper type definitions * Accessible dropdown menu with keyboard navigation * External link indicators for clarity ## Supported Platforms * **ChatGPT** - Opens query in OpenAI's ChatGPT with search hints * **Claude** - Opens query in Anthropic's Claude AI * **T3 Chat** - Opens query in T3 Chat platform * **Scira AI** - Opens query in Scira's AI assistant * **v0** - Opens query in Vercel's v0 platform * **Cursor** - Opens query in Cursor AI editor ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### ``, ``, ``, ``, ``, `` ", }, }} /> ### ``, ``, `` Additional composable components for custom dropdown menu items, labels, and separators that follow the same props pattern as their underlying radix-ui counterparts. --- title: Audio Player description: A composable audio player component built on media-chrome, with shadcn styling and flexible controls. --- # Audio Player The `AudioPlayer` component provides a flexible and customizable audio playback interface built on top of media-chrome. It features a composable architecture that allows you to build audio experiences with custom controls, metadata display, and seamless integration with AI-generated audio content. ## Installation ## Features * Built on media-chrome for reliable audio playback * Fully composable architecture with granular control components * ButtonGroup integration for cohesive control layout * Individual control components (play, seek, volume, etc.) * Flexible layout with customizable control bars * CSS custom properties for deep theming * Shadcn/ui Button component styling * Responsive design that works across devices * Full TypeScript support with proper types for all components ## Variants ### AI SDK Speech Result The `AudioPlayer` component can be used to play audio from an AI SDK Speech Result. ### Remote Audio The `AudioPlayer` component can be used to play remote audio files. ## Props ### `` Root MediaController component. Accepts all MediaController props except `audio` (which is set to `true` by default). , "audio">', }, }} /> ### `` The audio element that contains the media source. Accepts either a remote URL or AI SDK Speech Result data. , "src">', }, }} /> ### `` Container for control buttons, wraps children in a ButtonGroup. ", }, }} /> ### `` Play/pause button wrapped in a shadcn Button component. ", }, }} /> ### `` Seek backward button wrapped in a shadcn Button component. ", }, }} /> ### `` Seek forward button wrapped in a shadcn Button component. ", }, }} /> ### `` Displays the current playback time, wrapped in ButtonGroupText. ", }, }} /> ### `` Seek slider for controlling playback position, wrapped in ButtonGroupText. ", }, }} /> ### `` Displays the total duration of the audio, wrapped in ButtonGroupText. ", }, }} /> ### `` Mute/unmute button, wrapped in ButtonGroupText. ", }, }} /> ### `` Volume slider control, wrapped in ButtonGroupText. ", }, }} /> --- title: Mic Selector description: A composable dropdown component for selecting audio input devices with permission handling and device change detection. --- # Mic Selector The `MicSelector` component provides a flexible and composable interface for selecting microphone input devices. Built on shadcn/ui's Command and Popover components, it features automatic device detection, permission handling, dynamic device list updates, and intelligent device name parsing. ## Installation ## Features * Fully composable architecture with granular control components * Automatic audio input device enumeration * Permission-based device name display * Real-time device change detection via devicechange events * Intelligent device label parsing with ID extraction * Controlled and uncontrolled component patterns * Responsive width matching between trigger and content * Built on shadcn/ui Command and Popover components * Full TypeScript support with proper types for all components ## Props ### `` Root Popover component that provides context for all child components. void", optional: true, }, defaultOpen: { description: "The default open state (uncontrolled).", type: "boolean", optional: true, default: "false", }, open: { description: "The open state (controlled).", type: "boolean", optional: true, }, onOpenChange: { description: "Callback fired when the open state changes. Automatically requests microphone permission when opened without permission.", type: "(open: boolean) => void", optional: true, }, "...props": { description: "Any other props are spread to the Popover component.", type: "React.ComponentProps", }, }} /> ### `` Button that opens the microphone selector popover. Automatically tracks its width to match the popover content. ", }, }} /> ### `` Displays the currently selected microphone name or a placeholder. ', }, }} /> ### `` Container for the Command component, rendered inside the popover. ", optional: true, }, "...props": { description: "Any other props are spread to the Command component.", type: "React.ComponentProps", }, }} /> ### `` Search input for filtering microphones. ", }, }} /> ### `` Wrapper for the list of microphone items. Uses render props pattern to provide access to device data. ReactNode", }, "...props": { description: "Any other props are spread to the CommandList component.", type: 'Omit, "children">', }, }} /> ### `` Message shown when no microphones match the search. ", }, }} /> ### `` Selectable item representing a microphone. ", }, }} /> ### `` Displays a formatted microphone label with intelligent device ID parsing. Automatically extracts and styles device IDs in the format (XXXX:XXXX). ', }, }} /> ## Hooks ### `useAudioDevices()` A custom hook for managing audio input devices. This hook is used internally by the `MicSelector` component but can also be used independently. ```tsx import { useAudioDevices } from "@repo/elements/mic-selector"; export default function Example() { const { devices, loading, error, hasPermission, loadDevices } = useAudioDevices(); return (
{loading &&

Loading devices...

} {error &&

Error: {error}

} {devices.map((device) => (
{device.label}
))} {!hasPermission && ( )}
); } ``` #### Return Value Promise", }, }} /> ## Behavior ### Permission Handling The component implements a two-stage permission approach: 1. **Without Permission**: Initially loads devices without requesting permission. Device labels may show as generic names (e.g., "Microphone 1"). 2. **With Permission**: When the popover is opened and permission hasn't been granted, automatically requests microphone access and displays actual device names. ### Device Label Parsing The `MicSelectorLabel` component intelligently parses device names that include hardware IDs in the format `(XXXX:XXXX)`. It splits the label into the device name and ID, styling the ID with muted text for better readability. For example: `"MacBook Pro Microphone (1a2b:3c4d)"` becomes: * Device name: `"MacBook Pro Microphone"` * Device ID: `"(1a2b:3c4d)"` (styled with muted color) ### Width Synchronization The `MicSelectorTrigger` uses a ResizeObserver to track its width and automatically synchronizes it with the `MicSelectorContent` popover width for a cohesive appearance. ### Device Change Detection The component listens for `devicechange` events (e.g., plugging/unplugging microphones) and automatically updates the device list in real-time. ## Accessibility * Uses semantic HTML with proper ARIA attributes via shadcn/ui components * Full keyboard navigation support through Command component * Screen reader friendly with proper labels and roles * Searchable device list for quick selection ## Notes * Requires a secure context (HTTPS or localhost) for microphone access * Browser may prompt user for microphone permission on first open * Device labels are only fully descriptive after permission is granted * Component handles cleanup of temporary media streams during permission requests * Uses Radix UI's `useControllableState` for flexible controlled/uncontrolled patterns --- title: Persona description: An animated AI visual component powered by Rive that responds to different states like listening, thinking, and speaking. --- # Persona The `Persona` component displays an animated AI visual that responds to different conversational states. Built with Rive WebGL2, it provides smooth, high-performance animations for various AI interaction states including idle, listening, thinking, speaking, and asleep. The component supports multiple visual variants to match different design aesthetics. ## Installation ## Features * Smooth state-based animations powered by Rive * Multiple visual variants (obsidian, mana, opal, halo, glint, command) * Responsive to five distinct states: idle, listening, thinking, speaking, and asleep * WebGL2-accelerated rendering for optimal performance * Customizable size and styling * Lifecycle callbacks for load, ready, pause, play, and stop events * TypeScript support with full type definitions ## Variants The Persona component comes with 6 distinct visual variants, each with its own unique aesthetic: ### Obsidian (Default) ### Mana ### Opal ### Halo ### Glint ### Command ## Props ### `` The root component that renders the animated AI visual. void", optional: true, }, onPause: { description: "Callback fired when the animation is paused.", type: 'RiveParameters["onPause"]', optional: true, }, onPlay: { description: "Callback fired when the animation starts playing.", type: 'RiveParameters["onPlay"]', optional: true, }, onStop: { description: "Callback fired when the animation is stopped.", type: 'RiveParameters["onStop"]', optional: true, }, }} /> ## States The Persona component responds to five distinct states, each triggering different animations: * **idle**: The default resting state when the AI is not active * **listening**: Displayed when the AI is actively listening to user input (e.g., during voice recording) * **thinking**: Shown when the AI is processing or generating a response * **speaking**: Active when the AI is delivering a response (e.g., text-to-speech output) * **asleep**: A dormant state for when the AI is inactive or in low-power mode ## React Strict Mode (Vite) The Persona component uses WebGL2 for rendering. Browsers limit the number of active WebGL2 contexts (\~8–16), and React Strict Mode (enabled by default in Vite dev) double-mounts components, which can exhaust that limit and crash the page. The component includes a built-in guard that defers WebGL2 initialization by one frame, preventing context creation during Strict Mode's throw-away mount. This means the component works in Vite dev mode out of the box — no configuration needed. If you still experience crashes (for example, when rendering many Persona instances simultaneously), reduce the number of concurrent Persona components on screen. ## Usage Examples ### Basic Usage ```tsx import { Persona } from "@repo/elements/persona"; export default function App() { return ; } ``` ### With State Management ```tsx import { Persona } from "@repo/elements/persona"; import { useState } from "react"; export default function App() { const [state, setState] = useState< "idle" | "listening" | "thinking" | "speaking" | "asleep" >("idle"); const startListening = () => setState("listening"); const startThinking = () => setState("thinking"); const startSpeaking = () => setState("speaking"); const reset = () => setState("idle"); return (
); } ``` ### With Custom Styling ```tsx import { Persona } from "@repo/elements/persona"; export default function App() { return ( ); } ``` ### With Lifecycle Callbacks ```tsx import { Persona } from "@repo/elements/persona"; export default function App() { return ( console.log("Animation ready")} onLoad={() => console.log("Starting to load")} onLoadError={(error) => console.error("Failed to load:", error)} onPlay={() => console.log("Animation playing")} onPause={() => console.log("Animation paused")} onStop={() => console.log("Animation stopped")} /> ); } ``` --- title: Speech Input description: A button component that captures voice input and converts it to text, with cross-browser support. --- # Speech Input The `SpeechInput` component provides an easy-to-use interface for capturing voice input in your application. It uses the Web Speech API for real-time transcription in supported browsers (Chrome, Edge), and falls back to MediaRecorder with an external transcription service for browsers that don't support Web Speech API (Firefox, Safari). ## Installation ## Features * Built on Web Speech API (SpeechRecognition) with MediaRecorder fallback * Cross-browser support (Chrome, Edge, Firefox, Safari) * Continuous speech recognition with interim results * Visual feedback with pulse animation when listening * Loading state during transcription processing * Automatic browser compatibility detection * Final transcript extraction and callbacks * Error handling and automatic state management * Extends shadcn/ui Button component * Full TypeScript support ## Props ### `` The component extends the shadcn/ui Button component, so all Button props are available. void", optional: true, }, onAudioRecorded: { description: "Callback for MediaRecorder fallback. Required for Firefox/Safari support. Receives recorded audio blob and should return transcribed text from an external service (e.g., OpenAI Whisper).", type: "(audioBlob: Blob) => Promise", optional: true, }, lang: { description: "Language for speech recognition.", type: "string", default: '"en-US"', optional: true, }, "...props": { description: "Any other props are spread to the Button component, including variant, size, disabled, etc.", type: "React.ComponentProps", }, }} /> ## Behavior ### Speech Recognition Modes The component automatically detects browser capabilities and uses the best available method: | Browser | Mode | Behavior | | --------------- | -------------- | ------------------------------------------------------ | | Chrome, Edge | Web Speech API | Real-time transcription, no server required | | Firefox, Safari | MediaRecorder | Records audio, sends to external transcription service | | Unsupported | Disabled | Button is disabled | ### Web Speech API Mode (Chrome, Edge) Uses the Web Speech API with the following configuration: * **Continuous**: Set to `true` to keep recognition active until manually stopped * **Interim Results**: Set to `true` to receive partial results during speech * **Language**: Configurable via `lang` prop, defaults to `"en-US"` ### MediaRecorder Mode (Firefox, Safari) When the Web Speech API is unavailable, the component falls back to recording audio: 1. Records audio using `MediaRecorder` API 2. On stop, creates an audio blob (`audio/webm`) 3. Calls `onAudioRecorded` with the blob 4. Waits for transcription result 5. Passes result to `onTranscriptionChange` **Note**: The `onAudioRecorded` prop is required for this mode to work. Without it, the button will be disabled in Firefox/Safari. ### Transcription Processing The component only calls `onTranscriptionChange` with **final transcripts**. Interim results (Web Speech API) are ignored to prevent incomplete text from being processed. ### Visual States * **Default State**: Standard button appearance with microphone icon * **Listening State**: Pulsing animation with accent colors to indicate active listening * **Processing State**: Loading spinner while waiting for transcription (MediaRecorder mode) * **Disabled State**: Button is disabled when no API is available or required props are missing ### Lifecycle 1. **Mount**: Detects available APIs and initializes appropriate mode 2. **Click**: Toggles between listening/recording and stopped states 3. **Stop (MediaRecorder)**: Processes audio and waits for transcription 4. **Unmount**: Stops recognition/recording and releases microphone ## Browser Support The component provides cross-browser support through a two-tier system: | Browser | API Used | Requirements | | ------- | -------------- | ---------------------- | | Chrome | Web Speech API | None | | Edge | Web Speech API | None | | Firefox | MediaRecorder | `onAudioRecorded` prop | | Safari | MediaRecorder | `onAudioRecorded` prop | For full cross-browser support, provide the `onAudioRecorded` callback that sends audio to a transcription service like OpenAI Whisper, Google Cloud Speech-to-Text, or AssemblyAI. ## Accessibility * Uses semantic button element via shadcn/ui Button * Visual feedback for listening state * Keyboard accessible (can be triggered with Space/Enter) * Screen reader friendly with proper button semantics ## Usage with MediaRecorder Fallback To support Firefox and Safari, provide an `onAudioRecorded` callback that sends audio to a transcription service: ```tsx const handleAudioRecorded = async (audioBlob: Blob): Promise => { const formData = new FormData(); formData.append("file", audioBlob, "audio.webm"); formData.append("model", "whisper-1"); const response = await fetch( "https://api.openai.com/v1/audio/transcriptions", { method: "POST", headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, }, body: formData, } ); const data = await response.json(); return data.text; }; console.log(text)} onAudioRecorded={handleAudioRecorded} />; ``` ## Notes * Requires a secure context (HTTPS or localhost) * Browser may prompt user for microphone permission * Only final transcripts trigger the `onTranscriptionChange` callback * Language is configurable via the `lang` prop * Continuous recognition continues until button is clicked again * Errors are logged to console and automatically stop recognition/recording * MediaRecorder fallback requires the `onAudioRecorded` prop to be provided * Audio is recorded in `audio/webm` format for the MediaRecorder fallback ## TypeScript The component includes full TypeScript definitions for the Web Speech API: * `SpeechRecognition` * `SpeechRecognitionEvent` * `SpeechRecognitionResult` * `SpeechRecognitionAlternative` * `SpeechRecognitionErrorEvent` These types are properly declared for both standard and webkit-prefixed implementations. --- title: Transcription description: A composable component for displaying interactive, synchronized transcripts from AI SDK transcribe() results with click-to-seek functionality. --- # Transcription The `Transcription` component provides a flexible render props interface for displaying audio transcripts with synchronized playback. It automatically highlights the current segment based on playback time and supports click-to-seek functionality for interactive navigation. ## Installation ## Features * Render props pattern for maximum flexibility * Automatic segment highlighting based on current time * Click-to-seek functionality for interactive navigation * Controlled and uncontrolled component patterns * Automatic filtering of empty segments * Visual state indicators (active, past, future) * Built on Radix UI's `useControllableState` for flexible state management * Full TypeScript support with AI SDK transcription types ## Props ### `` Root component that provides context and manages transcript state. Uses render props pattern for rendering segments. void", optional: true, }, children: { description: "Render function that receives each segment and its index.", type: "(segment: TranscriptionSegment, index: number) => ReactNode", }, "...props": { description: "Any other props are spread to the root div element.", type: 'Omit, "children">', }, }} /> ### `` Individual segment button with automatic state styling and click-to-seek functionality. ', }, }} /> ## Behavior ### Render Props Pattern The component uses a render props pattern where the `children` prop is a function that receives each segment and its index. This provides maximum flexibility for custom rendering while still benefiting from automatic state management and context. ### Segment Highlighting Segments are automatically styled based on their relationship to the current playback time: * **Active** (`isActive`): When `currentTime` is within the segment's time range. Styled with primary color. * **Past** (`isPast`): When `currentTime` is after the segment's end time. Styled with muted foreground. * **Future**: When `currentTime` is before the segment's start time. Styled with dimmed muted foreground. ### Click-to-Seek When `onSeek` is provided, segments become interactive buttons. Clicking a segment calls `onSeek` with the segment's start time, allowing your audio/video player to seek to that position. ### Empty Segment Filtering The component automatically filters out segments with empty or whitespace-only text to avoid rendering unnecessary elements. ### State Management Uses Radix UI's `useControllableState` hook to support both controlled and uncontrolled patterns. When `currentTime` is provided, the component operates in controlled mode. Otherwise, it maintains its own internal state. ## Data Format The component expects segments from the AI SDK `transcribe()` function: ```ts type TranscriptionSegment = { text: string; startSecond: number; endSecond: number; }; ``` ## Styling The component uses data attributes for custom styling: * `data-slot="transcription"`: Root container * `data-slot="transcription-segment"`: Individual segment button * `data-active`: Present on the currently playing segment * `data-index`: The segment's index in the array Default segment appearance: * Active segment: `text-primary` (primary brand color) * Past segments: `text-muted-foreground` * Future segments: `text-muted-foreground/60` (dimmed) * Interactive segments: `cursor-pointer hover:text-foreground` * Non-interactive segments: `cursor-default` ## Accessibility * Uses semantic ` ); } ``` #### Return Value void", }, open: { description: "Whether the dialog is currently open.", type: "boolean", }, setOpen: { description: "Function to control the dialog open state.", type: "(open: boolean) => void", }, }} /> --- title: Canvas description: A React Flow-based canvas component for building interactive node-based interfaces. --- # Canvas The `Canvas` component provides a React Flow-based canvas for building interactive node-based interfaces. It comes pre-configured with sensible defaults for AI applications, including panning, zooming, and selection behaviors. The Canvas component is designed to be used with the [Node](/components/node) and [Edge](/components/edge) components. See the [Workflow](/examples/workflow) demo for a full example. ## Installation ## Features * Pre-configured React Flow canvas with AI-optimized defaults * Pan on scroll enabled for intuitive navigation * Selection on drag for multi-node operations * Customizable background color using CSS variables * Delete key support (Backspace and Delete keys) * Auto-fit view to show all nodes * Disabled double-click zoom for better UX * Disabled pan on drag to prevent accidental canvas movement * Fully compatible with React Flow props and API ## Props ### `` --- title: Connection description: A custom connection line component for React Flow-based canvases with animated bezier curve styling. --- # Connection The `Connection` component provides a styled connection line for React Flow canvases. It renders an animated bezier curve with a circle indicator at the target end, using consistent theming through CSS variables. The Connection component is designed to be used with the [Canvas](/components/canvas) component. See the [Workflow](/examples/workflow) demo for a full example. ## Installation ## Features * Smooth bezier curve animation for connection lines * Visual indicator circle at the target position * Theme-aware styling using CSS variables * Cubic bezier curve calculation for natural flow * Lightweight implementation with minimal props * Full TypeScript support with React Flow types * Compatible with React Flow's connection system ## Props ### `` --- title: Controls description: A styled controls component for React Flow-based canvases with zoom and fit view functionality. --- # Controls The `Controls` component provides interactive zoom and fit view controls for React Flow canvases. It includes a modern, themed design with backdrop blur and card styling. The Controls component is designed to be used with the [Canvas](/components/canvas) component. See the [Workflow](/examples/workflow) demo for a full example. ## Installation ## Features * Zoom in/out controls * Fit view button to center and scale content * Rounded pill design with backdrop blur * Theme-aware card background * Subtle drop shadow for depth * Full TypeScript support * Compatible with all React Flow control features ## Props ### `` ", }, }} /> --- title: Edge description: Customizable edge components for React Flow canvases with animated and temporary states. --- # Edge The `Edge` component provides two pre-styled edge types for React Flow canvases: `Temporary` for dashed temporary connections and `Animated` for connections with animated indicators. The Edge component is designed to be used with the [Canvas](/components/canvas) component. See the [Workflow](/examples/workflow) demo for a full example. ## Installation ## Features * Two distinct edge types: Temporary and Animated * Temporary edges use dashed lines with ring color * Animated edges include a moving circle indicator * Automatic handle position calculation * Smart offset calculation based on handle type and position * Uses Bezier curves for smooth, natural-looking connections * Fully compatible with React Flow's edge system * Type-safe implementation with TypeScript ## Edge Types ### `Edge.Temporary` A dashed edge style for temporary or preview connections. Uses a simple Bezier path with a dashed stroke pattern. ### `Edge.Animated` A solid edge with an animated circle that moves along the path. The animation repeats indefinitely with a 2-second duration, providing visual feedback for active connections. ## Props Both edge types accept standard React Flow `EdgeProps`: --- title: Node description: A composable node component for React Flow-based canvases with Card-based styling. --- # Node The `Node` component provides a composable, Card-based node for React Flow canvases. It includes support for connection handles, structured layouts, and consistent styling using shadcn/ui components. The Node component is designed to be used with the [Canvas](/components/canvas) component. See the [Workflow](/examples/workflow) demo for a full example. ## Installation ## Features * Built on shadcn/ui Card components for consistent styling * Automatic handle placement (left for target, right for source) * Composable sub-components (Header, Title, Description, Action, Content, Footer) * Semantic structure for organizing node information * Pre-styled sections with borders and backgrounds * Responsive sizing with fixed small width * Full TypeScript support with proper type definitions * Compatible with React Flow's node system ## Props ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> ### `` ", }, }} /> --- title: Panel description: A styled panel component for React Flow-based canvases to position custom UI elements. --- # Panel The `Panel` component provides a positioned container for custom UI elements on React Flow canvases. It includes modern card styling with backdrop blur and flexible positioning options. The Panel component is designed to be used with the [Canvas](/components/canvas) component. See the [Workflow](/examples/workflow) demo for a full example. ## Installation ## Features * Flexible positioning (top-left, top-right, bottom-left, bottom-right, top-center, bottom-center) * Rounded pill design with backdrop blur * Theme-aware card background * Flexbox layout for easy content alignment * Subtle drop shadow for depth * Full TypeScript support * Compatible with React Flow's panel system ## Props ### `` ", }, }} /> --- title: Toolbar description: A styled toolbar component for React Flow nodes with flexible positioning and custom actions. --- # Toolbar The `Toolbar` component provides a positioned toolbar that attaches to nodes in React Flow canvases. It features modern card styling with backdrop blur and flexbox layout for action buttons and controls. The Toolbar component is designed to be used with the [Node](/components/node) component. See the [Workflow](/examples/workflow) demo for a full example. ## Installation ## Features * Attaches to any React Flow node * Bottom positioning by default * Rounded card design with border * Theme-aware background styling * Flexbox layout with gap spacing * Full TypeScript support * Compatible with all React Flow NodeToolbar features ## Props ### `` ", }, }} /> --- title: Chatbot description: An example of how to use the AI Elements to build a chatbot. --- # Chatbot ## Tutorial Let's walk through how to build a chatbot using AI Elements and AI SDK. Our example will include reasoning, web search with citations, and a model picker. ### Setup First, set up a new Next.js repo and cd into it by running the following command (make sure you choose to use Tailwind the project setup): npm pnpm yarn bun ```bash npx create-next-app@latest ai-chatbot && cd ai-chatbot ``` ```bash pnpm dlx create-next-app@latest ai-chatbot && cd ai-chatbot ``` ```bash yarn dlx create-next-app@latest ai-chatbot && cd ai-chatbot ``` ```bash bun x create-next-app@latest ai-chatbot && cd ai-chatbot ``` Run the following command to install AI Elements. This will also set up shadcn/ui if you haven't already configured it: npm pnpm yarn bun ```bash npx ai-elements@latest ``` ```bash pnpm dlx ai-elements@latest ``` ```bash yarn dlx ai-elements@latest ``` ```bash bun x ai-elements@latest ``` Now, install the AI SDK dependencies: npm pnpm yarn bun ```bash npm i ai @ai-sdk/react zod ``` ```bash pnpm add ai @ai-sdk/react zod ``` ```bash yarn add ai @ai-sdk/react zod ``` ```bash bun add ai @ai-sdk/react zod ``` In order to use the providers, let's configure an AI Gateway API key. Create a `.env.local` in your root directory and navigate [here](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%2Fapi-keys\&title=Get%20your%20AI%20Gateway%20key) to create a token, then paste it in your `.env.local`. We're now ready to start building our app! ### Client In your `app/page.tsx`, replace the code with the file below. Here, we use the `PromptInput` component with its compound components to build a rich input experience with file attachments, model picker, and action menu. The input component uses the new `PromptInputMessage` type for handling both text and file attachments. The whole chat lives in a `Conversation`. We switch on `message.parts` and render the respective part within `Message`, `Reasoning`, and `Sources`. We also use `status` from `useChat` to stream reasoning tokens, as well as render `Loader`. Install Sonner for the toast notification used in `app/page.tsx`: npm pnpm yarn bun ```bash npm i sonner ``` ```bash pnpm add sonner ``` ```bash yarn add sonner ``` ```bash bun add sonner ``` Add `` from `sonner` to your `app/layout.tsx` so toast notifications are visible. ### Server Create a new route handler `app/api/chat/route.ts` and paste in the following code. We're using `perplexity/sonar` for web search because by default the model returns search results. We also pass `sendSources` and `sendReasoning` to `toUIMessageStreamResponse` in order to receive as parts on the frontend. The handler now also accepts file attachments from the client. ```ts title="app/api/chat/route.ts" import { streamText, UIMessage, convertToModelMessages } from "ai"; // Allow streaming responses up to 30 seconds export const maxDuration = 30; export async function POST(req: Request) { const { messages, model, webSearch, }: { messages: UIMessage[]; model: string; webSearch: boolean; } = await req.json(); const result = streamText({ model: webSearch ? "perplexity/sonar" : model, messages: await convertToModelMessages(messages), system: "You are a helpful assistant that can answer questions and help with tasks", }); // send sources and reasoning back to the client return result.toUIMessageStreamResponse({ sendSources: true, sendReasoning: true, }); } ``` You now have a working chatbot app with file attachment support! The chatbot can handle both text and file inputs through the action menu. Feel free to explore other components like [`Tool`](/components/tool) or [`Task`](/components/task) to extend your app, or view the other examples. --- title: IDE description: An example of how to use the AI Elements to build an AI-powered IDE with file navigation, code display, terminal output, and an integrated chat assistant. --- # IDE ## Tutorial Let's walk through how to build an AI-powered IDE using AI Elements. Our example will include a file tree, code block viewer, terminal output, task queue, and chat interface with streaming responses. ### Setup First, set up a new Next.js repo and cd into it by running the following command (make sure you choose to use Tailwind in the project setup): npm pnpm yarn bun ```bash npx create-next-app@latest ai-ide && cd ai-ide ``` ```bash pnpm dlx create-next-app@latest ai-ide && cd ai-ide ``` ```bash yarn dlx create-next-app@latest ai-ide && cd ai-ide ``` ```bash bun x create-next-app@latest ai-ide && cd ai-ide ``` Run the following command to install AI Elements. This will also set up shadcn/ui if you haven't already configured it: npm pnpm yarn bun ```bash npx ai-elements@latest ``` ```bash pnpm dlx ai-elements@latest ``` ```bash yarn dlx ai-elements@latest ``` ```bash bun x ai-elements@latest ``` Now, install the required dependencies: npm pnpm yarn bun ```bash npm i nanoid shiki lucide-react ``` ```bash pnpm add nanoid shiki lucide-react ``` ```bash yarn add nanoid shiki lucide-react ``` ```bash bun add nanoid shiki lucide-react ``` We're now ready to start building our IDE! ### Client Let's build the IDE step by step. We'll create the component structure with a three-panel layout: file tree on the left, code and terminal in the center, and the AI chat on the right. First, import the necessary AI Elements components in your `app/page.tsx`: ## Key Features The IDE example demonstrates several powerful features: * **File Tree Navigation**: The `FileTree` component displays a hierarchical file structure with expandable folders and file selection. * **Code Display**: The `CodeBlock` component renders syntax-highlighted code with line numbers and a copy button. * **Terminal Output**: The `Terminal` component shows streaming build output with ANSI color support. * **Plan Component**: The `Plan` displays the AI's implementation strategy with collapsible sections. * **Task Queue**: The `Queue` component organizes pending and completed tasks in separate sections. * **Chat Interface**: The `Conversation` and `Message` components create a streaming chat experience. * **Checkpoints**: The `Checkpoint` component allows users to mark and restore conversation states. * **Streaming Support**: All components support real-time streaming for a responsive user experience. You now have a working AI-powered IDE interface! Feel free to extend it with additional features like file editing, multiple tabs, or connect it to a real AI backend using the AI SDK. --- title: v0 clone description: An example of how to use the AI Elements to build a v0 clone. --- # v0 clone ## Tutorial Let's walk through how to build a v0 clone using AI Elements and the [v0 Platform API](https://v0.dev/docs/api/platform). ### Setup First, set up a new Next.js repo and cd into it by running the following command (make sure you choose to use Tailwind the project setup): npm pnpm yarn bun ```bash npx create-next-app@latest v0-clone && cd v0-clone ``` ```bash pnpm dlx create-next-app@latest v0-clone && cd v0-clone ``` ```bash yarn dlx create-next-app@latest v0-clone && cd v0-clone ``` ```bash bun x create-next-app@latest v0-clone && cd v0-clone ``` Run the following command to install shadcn/ui and AI Elements. npm pnpm yarn bun ```bash npx shadcn@latest init && npx ai-elements@latest ``` ```bash pnpm dlx shadcn@latest init && npx ai-elements@latest ``` ```bash yarn dlx shadcn@latest init && npx ai-elements@latest ``` ```bash bun x shadcn@latest init && npx ai-elements@latest ``` Now, install the v0 sdk: npm pnpm yarn bun ```bash npm i v0-sdk ``` ```bash pnpm add v0-sdk ``` ```bash yarn add v0-sdk ``` ```bash bun add v0-sdk ``` In order to use the providers, let's configure a v0 API key. Create a `.env.local` in your root directory and navigate to your [v0 account settings](https://v0.dev/chat/settings/keys) to create a token, then paste it in your `.env.local` as `V0_API_KEY`. We're now ready to start building our app! ### Client In your `app/page.tsx`, replace the code with the file below. Here, we use `Conversation` to wrap the conversation code, and the `WebPreview` component to render the URL returned from the v0 API. In this case, we'll also edit the base component `components/ai-elements/web-preview.tsx` in order to best match with our theme. ```tsx title="components/ai-elements/web-preview.tsx" highlight="5,24" return (
{children}
); }; export type WebPreviewNavigationProps = ComponentProps<'div'>; export const WebPreviewNavigation = ({ className, children, ...props }: WebPreviewNavigationProps) => (
{children}
); ``` ### Server Create a new route handler `app/api/chat/route.ts` and paste in the following code. We use the v0 SDK to manage chats. ```ts title="app/api/chat/route.ts" import { NextRequest, NextResponse } from "next/server"; import { v0 } from "v0-sdk"; export async function POST(request: NextRequest) { try { const { message, chatId } = await request.json(); if (!message) { return NextResponse.json( { error: "Message is required" }, { status: 400 } ); } let chat; if (chatId) { // continue existing chat chat = await v0.chats.sendMessage({ chatId: chatId, message, }); } else { // create new chat chat = await v0.chats.create({ message, }); } return NextResponse.json({ id: chat.id, demo: chat.demo, }); } catch (error) { console.error("V0 API Error:", error); return NextResponse.json( { error: "Failed to process request" }, { status: 500 } ); } } ``` To start your server, run `pnpm dev`, navigate to `localhost:3000` and try building an app! You now have a working v0 clone you can build off of! Feel free to explore the [v0 Platform API](https://v0.dev/docs/api/platform) and components like [`Reasoning`](/components/reasoning) and [`Task`](/components/task) to extend your app, or view the other examples. --- title: Workflow description: An example of how to use the AI Elements to build a workflow visualization with interactive nodes and animated connections. --- # Workflow ## Tutorial Let's walk through how to build a workflow visualization using AI Elements. Our example will include custom nodes with headers, content, and footers, along with animated and temporary edge types. ### Setup First, set up a new Next.js repo and cd into it by running the following command (make sure you choose to use Tailwind in the project setup): npm pnpm yarn bun ```bash npx create-next-app@latest ai-workflow && cd ai-workflow ``` ```bash pnpm dlx create-next-app@latest ai-workflow && cd ai-workflow ``` ```bash yarn dlx create-next-app@latest ai-workflow && cd ai-workflow ``` ```bash bun x create-next-app@latest ai-workflow && cd ai-workflow ``` Run the following command to install AI Elements. This will also set up shadcn/ui if you haven't already configured it: npm pnpm yarn bun ```bash npx ai-elements@latest ``` ```bash pnpm dlx ai-elements@latest ``` ```bash yarn dlx ai-elements@latest ``` ```bash bun x ai-elements@latest ``` Now, install the required dependencies: npm pnpm yarn bun ```bash npm i @xyflow/react ``` ```bash pnpm add @xyflow/react ``` ```bash yarn add @xyflow/react ``` ```bash bun add @xyflow/react ``` We're now ready to start building our workflow! ### Client Let's build the workflow visualization step by step. We'll create the component structure, define our nodes and edges, and configure the canvas. #### Import the components First, let's build the interface: ### Key Features The workflow visualization demonstrates several powerful features: * **Custom Node Components**: Each node uses the compound components (`NodeHeader`, `NodeTitle`, `NodeDescription`, `NodeContent`, `NodeFooter`) for consistent, structured layouts. * **Node Toolbars**: The `Toolbar` component attaches contextual actions (like Edit and Delete buttons) to individual nodes, appearing when hovering or selecting them. * **Handle Configuration**: Nodes can have source and/or target handles, controlling which connections are possible. * **Multiple Edge Types**: The `animated` type shows active data flow, while `temporary` indicates conditional or error paths. * **Custom Connection Lines**: The `Connection` component provides styled bezier curves when dragging new connections between nodes. * **Interactive Controls**: The `Controls` component adds zoom in/out and fit view buttons with a modern, themed design. * **Custom UI Panels**: The `Panel` component allows you to position custom UI elements (like buttons, filters, or legends) anywhere on the canvas. * **Automatic Layout**: The `Canvas` component auto-fits the view and provides pan/zoom controls out of the box. You now have a working workflow visualization! Feel free to explore dynamic workflows by connecting this to AI-generated process flows, or extend it with interactive editing capabilities using React Flow's built-in features.