---
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 (
);
}
```
### 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 (
);
}
```
## 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 (
);
};
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 executionYou 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 (
);
};
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 (
);
};
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 (
);
};
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 (
);
};
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 (