AI Elements

PreviousNext

A collection of React components designed for building AI-powered applications with shadcn/ui.

AI Elements are a collection of React components specifically designed for building AI-powered applications. These components integrate seamlessly with the Vercel AI SDK and provide a consistent, accessible interface for AI interactions.

What are AI Elements?

AI Elements are pre-built React components that handle common AI application patterns:

  • Chat interfaces with streaming responses
  • Message handling with user and assistant roles
  • Tool execution with real-time feedback
  • File attachments and image handling
  • Loading states and error handling
  • Conversation management with auto-scrolling

Installation

AI Elements are included with shadcn/ui v4. To use them, you need to install the AI SDK:

pnpm add ai @ai-sdk/openai

Core Components

Message Components

Message

The base component for displaying individual messages in a conversation.

import {
  Message,
  MessageAvatar,
  MessageContent,
} from "@/components/ai-elements/message"
 
export function ChatMessage({ message }) {
  return (
    <Message from={message.role}>
      <MessageAvatar src={message.avatar} name={message.name} />
      <MessageContent variant="contained">{message.content}</MessageContent>
    </Message>
  )
}

Props:

  • from: "user" | "assistant" - The role of the message sender
  • variant: "contained" | "flat" - Visual style variant

MessageContent

Container for message content with built-in styling for user and assistant messages.

<MessageContent variant="contained">
  <p>Your message content here</p>
</MessageContent>

MessageAvatar

Avatar component for displaying user and assistant profile pictures.

<MessageAvatar src="/path/to/avatar.jpg" name="John Doe" />

Conversation Components

Conversation

The main container for chat conversations with auto-scrolling behavior.

import {
  Conversation,
  ConversationContent,
} from "@/components/ai-elements/conversation"
 
export function ChatInterface() {
  return (
    <Conversation>
      <ConversationContent>{/* Your messages here */}</ConversationContent>
    </Conversation>
  )
}

ConversationEmptyState

Displays when there are no messages in the conversation.

import { ConversationEmptyState } from "@/components/ai-elements/conversation"
 
;<ConversationEmptyState
  title="No messages yet"
  description="Start a conversation to see messages here"
  icon={<ChatIcon />}
/>

ConversationScrollButton

A button that appears when the user has scrolled up, allowing them to return to the bottom.

import { ConversationScrollButton } from "@/components/ai-elements/conversation"
 
;<ConversationScrollButton />

Input Components

PromptInput

A comprehensive input component for chat interfaces with file attachment support.

import {
  PromptInput,
  PromptInputAttachment,
  PromptInputAttachments,
  PromptInputBody,
  PromptInputSubmit,
  PromptInputTextarea,
  PromptInputToolbar,
} from "@/components/ai-elements/prompt-input"
 
export function ChatInput({ onSubmit }) {
  return (
    <PromptInput onSubmit={onSubmit}>
      <PromptInputBody>
        <PromptInputAttachments>
          {(attachment) => <PromptInputAttachment data={attachment} />}
        </PromptInputAttachments>
        <PromptInputTextarea placeholder="What would you like to know?" />
      </PromptInputBody>
      <PromptInputToolbar>
        <PromptInputSubmit />
      </PromptInputToolbar>
    </PromptInput>
  )
}

Features:

  • File drag & drop support
  • Image preview
  • Auto-resizing textarea
  • Keyboard shortcuts (Enter to send, Shift+Enter for new line)
  • Paste file support

PromptInputSubmit

Submit button with loading states based on chat status.

<PromptInputSubmit status="streaming" />

Status options:

  • "submitted" - Shows loading spinner
  • "streaming" - Shows stop icon
  • "error" - Shows error icon
  • undefined - Shows send icon

Response Components

Response

Component for displaying AI responses with streaming support.

import { Response } from "@/components/ai-elements/response"
 
export function AIResponse({ content }) {
  return <Response>{content}</Response>
}

Utility Components

Loader

Animated loading spinner for AI processing states.

import { Loader } from "@/components/ai-elements/loader"
 
;<Loader size={16} />

Suggestions

Horizontal scrollable list of suggestion buttons.

import { Suggestion, Suggestions } from "@/components/ai-elements/suggestion"
 
export function SuggestionList({ suggestions, onSuggestionClick }) {
  return (
    <Suggestions>
      {suggestions.map((suggestion) => (
        <Suggestion
          key={suggestion}
          suggestion={suggestion}
          onClick={onSuggestionClick}
        />
      ))}
    </Suggestions>
  )
}

Tool Components

Tool

Collapsible component for displaying tool execution details.

import {
  Tool,
  ToolContent,
  ToolHeader,
  ToolInput,
  ToolOutput,
} from "@/components/ai-elements/tool"
 
export function ToolExecution({ tool }) {
  return (
    <Tool>
      <ToolHeader title={tool.name} type={tool.type} state={tool.state} />
      <ToolContent>
        <ToolInput input={tool.input} />
        <ToolOutput output={tool.output} errorText={tool.errorText} />
      </ToolContent>
    </Tool>
  )
}

Tool States:

  • "input-streaming" - Tool is receiving input
  • "input-available" - Tool is processing
  • "output-available" - Tool completed successfully
  • "output-error" - Tool encountered an error

Media Components

GeneratedImage

Component for displaying AI-generated images.

import { GeneratedImage } from "@/components/ai-elements/image"
 
;<GeneratedImage
  base64={imageData.base64}
  mediaType={imageData.mediaType}
  alt="AI generated image"
/>

Action Components

Actions

Container for message action buttons (retry, copy, etc.).

import { Action, Actions } from "@/components/ai-elements/actions"
 
export function MessageActions() {
  return (
    <Actions>
      <Action tooltip="Retry message" label="Retry">
        <RetryIcon />
      </Action>
      <Action tooltip="Copy message" label="Copy">
        <CopyIcon />
      </Action>
    </Actions>
  )
}

Props:

  • tooltip: Optional tooltip text
  • label: Accessibility label
  • variant: Button variant
  • size: Button size

Context Components

Context

Displays AI model context usage and cost information.

import {
  Context,
  ContextContent,
  ContextContentBody,
  ContextContentFooter,
  ContextContentHeader,
  ContextInputUsage,
  ContextOutputUsage,
  ContextTrigger,
} from "@/components/ai-elements/context"
 
export function ContextUsage({ usage, modelId }) {
  return (
    <Context
      usedTokens={usage.inputTokens + usage.outputTokens}
      maxTokens={8000}
      usage={usage}
      modelId={modelId}
    >
      <ContextTrigger />
      <ContextContent>
        <ContextContentHeader />
        <ContextContentBody>
          <ContextInputUsage />
          <ContextOutputUsage />
        </ContextContentBody>
        <ContextContentFooter />
      </ContextContent>
    </Context>
  )
}

Features:

  • Token usage visualization
  • Cost estimation
  • Progress indicators
  • Hover card display

Artifact Components

Artifact

Container for AI-generated artifacts (tables, charts, etc.).

import {
  Artifact,
  ArtifactAction,
  ArtifactActions,
  ArtifactClose,
  ArtifactContent,
  ArtifactDescription,
  ArtifactHeader,
  ArtifactTitle,
} from "@/components/ai-elements/artifact"
 
export function ArtifactDisplay({ title, description, children }) {
  return (
    <Artifact>
      <ArtifactHeader>
        <div>
          <ArtifactTitle>{title}</ArtifactTitle>
          <ArtifactDescription>{description}</ArtifactDescription>
        </div>
        <ArtifactActions>
          <ArtifactAction tooltip="Download" icon={DownloadIcon} />
          <ArtifactAction tooltip="Share" icon={ShareIcon} />
          <ArtifactClose />
        </ArtifactActions>
      </ArtifactHeader>
      <ArtifactContent>{children}</ArtifactContent>
    </Artifact>
  )
}

Source Components

Sources

Displays source citations and references.

import {
  Source,
  Sources,
  SourcesContent,
  SourcesTrigger,
} from "@/components/ai-elements/sources"
 
export function SourceCitations({ sources }) {
  return (
    <Sources>
      <SourcesTrigger count={sources.length} />
      <SourcesContent>
        {sources.map((source, index) => (
          <Source key={index} href={source.url} title={source.title} />
        ))}
      </SourcesContent>
    </Sources>
  )
}

Branch Components

Branch

Manages multiple conversation branches or alternative responses.

import {
  Branch,
  BranchMessages,
  BranchNext,
  BranchPage,
  BranchPrevious,
  BranchSelector,
} from "@/components/ai-elements/branch"
 
export function BranchingChat({ messages }) {
  return (
    <Branch defaultBranch={0}>
      <BranchMessages>
        {messages.map((branch, index) => (
          <div key={index}>
            {branch.map((message) => (
              <Message key={message.id} from={message.role}>
                <MessageContent>{message.content}</MessageContent>
              </Message>
            ))}
          </div>
        ))}
      </BranchMessages>
      <BranchSelector from="assistant">
        <BranchPrevious />
        <BranchPage />
        <BranchNext />
      </BranchSelector>
    </Branch>
  )
}

Features:

  • Navigate between different conversation branches
  • Automatic branch detection
  • Keyboard navigation support

Chain of Thought Components

ChainOfThought

Displays AI reasoning process step by step.

import {
  ChainOfThought,
  ChainOfThoughtContent,
  ChainOfThoughtHeader,
  ChainOfThoughtImage,
  ChainOfThoughtSearchResult,
  ChainOfThoughtSearchResults,
  ChainOfThoughtStep,
} from "@/components/ai-elements/chain-of-thought"
 
export function ReasoningDisplay({ steps }) {
  return (
    <ChainOfThought>
      <ChainOfThoughtHeader>Analysis Process</ChainOfThoughtHeader>
      <ChainOfThoughtContent>
        {steps.map((step, index) => (
          <ChainOfThoughtStep
            key={index}
            label={step.label}
            description={step.description}
            status={step.status}
            icon={step.icon}
          >
            {step.content}
          </ChainOfThoughtStep>
        ))}
        <ChainOfThoughtSearchResults>
          <ChainOfThoughtSearchResult>
            Search Result 1
          </ChainOfThoughtSearchResult>
          <ChainOfThoughtSearchResult>
            Search Result 2
          </ChainOfThoughtSearchResult>
        </ChainOfThoughtSearchResults>
        <ChainOfThoughtImage caption="Analysis visualization">
          <img src="/analysis-chart.png" alt="Analysis" />
        </ChainOfThoughtImage>
      </ChainOfThoughtContent>
    </ChainOfThought>
  )
}

Reasoning Components

Reasoning

Shows AI thinking process with auto-collapse behavior.

import {
  Reasoning,
  ReasoningContent,
  ReasoningTrigger,
} from "@/components/ai-elements/reasoning"
 
export function AIReasoning({ isStreaming, reasoning }) {
  return (
    <Reasoning isStreaming={isStreaming} defaultOpen={true}>
      <ReasoningTrigger />
      <ReasoningContent>{reasoning}</ReasoningContent>
    </Reasoning>
  )
}

Features:

  • Auto-opens during streaming
  • Auto-closes after completion
  • Duration tracking
  • Collapsible interface

Complete Example

Here's a complete chat interface using AI Elements:

"use client"
 
import { useChat } from "ai/react"
 
import {
  Conversation,
  ConversationContent,
  ConversationEmptyState,
  ConversationScrollButton,
  Loader,
  Message,
  MessageAvatar,
  MessageContent,
  PromptInput,
  PromptInputBody,
  PromptInputSubmit,
  PromptInputTextarea,
  PromptInputToolbar,
  Response,
} from "@/components/ai-elements"
 
export function ChatInterface() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } =
    useChat()
 
  return (
    <div className="flex h-screen flex-col">
      <Conversation>
        <ConversationContent>
          {messages.length === 0 ? (
            <ConversationEmptyState
              title="Start a conversation"
              description="Ask me anything!"
            />
          ) : (
            messages.map((message) => (
              <Message key={message.id} from={message.role}>
                <MessageAvatar
                  src={
                    message.role === "user"
                      ? "/user-avatar.jpg"
                      : "/ai-avatar.jpg"
                  }
                  name={message.role === "user" ? "You" : "AI"}
                />
                <MessageContent>
                  <Response>{message.content}</Response>
                </MessageContent>
              </Message>
            ))
          )}
          {isLoading && (
            <Message from="assistant">
              <MessageAvatar src="/ai-avatar.jpg" name="AI" />
              <MessageContent>
                <Loader />
              </MessageContent>
            </Message>
          )}
        </ConversationContent>
        <ConversationScrollButton />
      </Conversation>
 
      <PromptInput onSubmit={handleSubmit}>
        <PromptInputBody>
          <PromptInputTextarea
            value={input}
            onChange={handleInputChange}
            placeholder="What would you like to know?"
          />
        </PromptInputBody>
        <PromptInputToolbar>
          <PromptInputSubmit />
        </PromptInputToolbar>
      </PromptInput>
    </div>
  )
}

Styling and Theming

AI Elements inherit your shadcn/ui theme configuration. They use CSS variables for colors and can be customized through your globals.css:

:root {
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 98%;
  /* ... other variables */
}

Integration with AI SDK

AI Elements are designed to work seamlessly with the Vercel AI SDK. Here's how to integrate them:

import { useChat } from "ai/react"
 
import { Message, MessageContent } from "@/components/ai-elements/message"
 
export function ChatWithAI() {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: "/api/chat",
  })
 
  return (
    <div>
      {messages.map((message) => (
        <Message key={message.id} from={message.role}>
          <MessageContent>{message.content}</MessageContent>
        </Message>
      ))}
 
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="Type your message..."
        />
        <button type="submit">Send</button>
      </form>
    </div>
  )
}

Best Practices

  1. Use semantic HTML: AI Elements use proper ARIA attributes for accessibility
  2. Handle loading states: Always show loading indicators during AI processing
  3. Provide feedback: Use tool components to show AI reasoning and actions
  4. Optimize for mobile: AI Elements are responsive by default
  5. Customize carefully: Modify components thoughtfully to maintain consistency

Accessibility

AI Elements are built with accessibility in mind:

  • Proper ARIA labels and roles
  • Keyboard navigation support
  • Screen reader compatibility
  • Focus management
  • Color contrast compliance

Next Steps