ai-sdk-elements

SKILL.md

AI SDK Elements

Overview

AI SDK Elements is a React component library built on shadcn/ui for AI-native applications. Part of Vercel's AI SDK ecosystem.

Requirements:

  • React 19 (no forwardRef patterns)
  • Tailwind CSS 4
  • shadcn/ui configured

Docs: https://ai-sdk.dev/elements

Quick Reference

# Install all components
npx ai-elements@latest

# Install specific component
npx ai-elements@latest add conversation
npx ai-elements@latest add message
npx ai-elements@latest add reasoning

# Alternative (shadcn CLI)
npx shadcn@latest add @ai-elements/conversation

Components install to @/components/ai-elements/


Core Components

Conversation (Chat Container)

Main wrapper with auto-scroll to bottom.

import {
  Conversation,
  ConversationContent,
  ConversationEmptyState,
  ConversationScrollButton,
} from '@/components/ai-elements/conversation';

<Conversation className="relative h-full">
  <ConversationContent>
    {messages.length === 0 ? (
      <ConversationEmptyState
        icon={<MessageSquareIcon />}
        title="Start a conversation"
        description="Ask me anything"
      />
    ) : (
      messages.map((msg) => (
        <Message key={msg.id} from={msg.role}>
          <MessageContent>{msg.content}</MessageContent>
        </Message>
      ))
    )}
  </ConversationContent>
  <ConversationScrollButton />
</Conversation>

Message

Individual chat message display.

import { Message, MessageContent } from '@/components/ai-elements/message';

<Message from="user">
  <MessageContent>Hello, can you help me?</MessageContent>
</Message>

<Message from="assistant">
  <MessageContent>{response}</MessageContent>
</Message>

Prompt Input

User input for chat.

import { PromptInput } from '@/components/ai-elements/prompt-input';

<PromptInput
  value={input}
  onChange={(e) => setInput(e.target.value)}
  onSubmit={handleSubmit}
  placeholder="Type a message..."
/>

AI Reasoning Components

Reasoning (Collapsible Thinking)

Auto-opens during streaming, collapses when done.

import {
  Reasoning,
  ReasoningTrigger,
  ReasoningContent,
} from '@/components/ai-elements/reasoning';

<Reasoning isStreaming={isStreaming} className="w-full">
  <ReasoningTrigger title="Thinking..." />
  <ReasoningContent>{reasoningText}</ReasoningContent>
</Reasoning>

Chain of Thought

Visual step-by-step reasoning with search results, images, progress.

import { ChainOfThought } from '@/components/ai-elements/chain-of-thought';

<ChainOfThought>
  <ChainOfThoughtStep>
    <ChainOfThoughtIcon><SearchIcon /></ChainOfThoughtIcon>
    <ChainOfThoughtContent>
      Searching for profiles...
      <ChainOfThoughtLinks>
        <ChainOfThoughtLink href="https://x.com">x.com</ChainOfThoughtLink>
        <ChainOfThoughtLink href="https://github.com">github.com</ChainOfThoughtLink>
      </ChainOfThoughtLinks>
    </ChainOfThoughtContent>
  </ChainOfThoughtStep>
</ChainOfThought>

Plan & Task

Display agent plans and individual tasks.

import { Plan, Task } from '@/components/ai-elements/plan';

<Plan title="Implementation Plan">
  <Task status="completed">Set up project structure</Task>
  <Task status="in_progress">Implement core features</Task>
  <Task status="pending">Write tests</Task>
</Plan>

Interactivity Components

Confirmation (Tool Approval)

Manage tool execution approval workflows.

import {
  Confirmation,
  ConfirmationRequest,
  ConfirmationAccepted,
  ConfirmationRejected,
  ConfirmationActions,
  ConfirmationAction,
} from '@/components/ai-elements/confirmation';

<Confirmation approval={tool.approval} state={tool.state}>
  <ConfirmationRequest>
    This tool wants to delete: <code>{tool.input?.filePath}</code>
    <br />Do you approve?
  </ConfirmationRequest>
  <ConfirmationAccepted>File deleted successfully</ConfirmationAccepted>
  <ConfirmationRejected>Action cancelled</ConfirmationRejected>
  <ConfirmationActions>
    <ConfirmationAction
      onClick={() => respondToConfirmationRequest({ approvalId, approved: false })}>
      Reject
    </ConfirmationAction>
    <ConfirmationAction
      onClick={() => respondToConfirmationRequest({ approvalId, approved: true })}>
      Approve
    </ConfirmationAction>
  </ConfirmationActions>
</Confirmation>

Suggestion (Quick Prompts)

Horizontal row of clickable suggestions.

import { Suggestions, Suggestion } from '@/components/ai-elements/suggestion';

const prompts = [
  'How do I get started?',
  'What can you help with?',
  'Show me examples',
];

<Suggestions>
  {prompts.map((prompt) => (
    <Suggestion
      key={prompt}
      suggestion={prompt}
      onClick={(text) => setInput(text)}
    />
  ))}
</Suggestions>

Tool

Display tool calls and results.

import { Tool, ToolContent, ToolResult } from '@/components/ai-elements/tool';

<Tool name="search_web">
  <ToolContent>
    Searching for: {tool.args.query}
  </ToolContent>
  <ToolResult>
    {tool.result}
  </ToolResult>
</Tool>

Checkpoint (Restore Points)

Mark and restore conversation history.

import {
  Checkpoint,
  CheckpointIcon,
  CheckpointTrigger,
} from '@/components/ai-elements/checkpoint';

<Checkpoint>
  <CheckpointIcon />
  <CheckpointTrigger onClick={() => restoreToCheckpoint(index)}>
    Restore to this point
  </CheckpointTrigger>
</Checkpoint>

Citation Components

Sources

Collapsible source citations.

import {
  Sources,
  SourcesTrigger,
  SourcesContent,
  Source,
} from '@/components/ai-elements/sources';

<Sources>
  <SourcesTrigger count={3} />
  <SourcesContent>
    <Source href="https://docs.example.com/api" title="API Documentation" />
    <Source href="https://example.com/guide" title="Getting Started Guide" />
    <Source href="https://example.com/faq" title="FAQ" />
  </SourcesContent>
</Sources>

Inline Citation

Citations within text content.

import { InlineCitation } from '@/components/ai-elements/inline-citation';

<p>
  According to the documentation
  <InlineCitation href="https://docs.example.com" index={1} />
  , you should...
</p>

Loading Components

Queue

Message queue/loading state.

import { Queue } from '@/components/ai-elements/queue';

<Queue>Processing your request...</Queue>

Shimmer

Skeleton loading placeholder.

import { Shimmer } from '@/components/ai-elements/shimmer';

{isLoading && <Shimmer className="h-20 w-full" />}

Utility Components

Model Selector

Switch between AI models.

import { ModelSelector } from '@/components/ai-elements/model-selector';

<ModelSelector
  models={['gpt-4', 'claude-3', 'gemini-pro']}
  selected={model}
  onSelect={setModel}
/>

Context

Display context information.

import { Context } from '@/components/ai-elements/context';

<Context title="Current Context">
  Working on: Project Alpha
  Files: 3 selected
</Context>

Complete Chat Example

'use client';

import { useState } from 'react';
import { useChat } from 'ai/react';
import {
  Conversation,
  ConversationContent,
  ConversationEmptyState,
  ConversationScrollButton,
} from '@/components/ai-elements/conversation';
import { Message, MessageContent } from '@/components/ai-elements/message';
import { PromptInput } from '@/components/ai-elements/prompt-input';
import { Reasoning, ReasoningTrigger, ReasoningContent } from '@/components/ai-elements/reasoning';
import { Suggestions, Suggestion } from '@/components/ai-elements/suggestion';
import { Sources, SourcesTrigger, SourcesContent, Source } from '@/components/ai-elements/sources';

export function Chat() {
  const { messages, input, setInput, handleSubmit, isLoading } = useChat();

  const suggestions = [
    'What can you help me with?',
    'Tell me about AI SDK',
    'How do I get started?',
  ];

  return (
    <div className="flex h-screen flex-col">
      <Conversation className="flex-1">
        <ConversationContent className="p-4">
          {messages.length === 0 ? (
            <>
              <ConversationEmptyState
                title="Welcome!"
                description="Ask me anything to get started"
              />
              <Suggestions className="mt-4">
                {suggestions.map((s) => (
                  <Suggestion key={s} suggestion={s} onClick={setInput} />
                ))}
              </Suggestions>
            </>
          ) : (
            messages.map((msg) => (
              <Message key={msg.id} from={msg.role}>
                <MessageContent>{msg.content}</MessageContent>

                {/* Show reasoning if available */}
                {msg.reasoning && (
                  <Reasoning isStreaming={isLoading && msg.id === messages.at(-1)?.id}>
                    <ReasoningTrigger />
                    <ReasoningContent>{msg.reasoning}</ReasoningContent>
                  </Reasoning>
                )}

                {/* Show sources if available */}
                {msg.sources?.length > 0 && (
                  <Sources>
                    <SourcesTrigger count={msg.sources.length} />
                    <SourcesContent>
                      {msg.sources.map((src, i) => (
                        <Source key={i} href={src.url} title={src.title} />
                      ))}
                    </SourcesContent>
                  </Sources>
                )}
              </Message>
            ))
          )}
        </ConversationContent>
        <ConversationScrollButton />
      </Conversation>

      <form onSubmit={handleSubmit} className="border-t p-4">
        <PromptInput
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="Type a message..."
          disabled={isLoading}
        />
      </form>
    </div>
  );
}

Styling

All components accept className prop for Tailwind customization:

<Message className="bg-muted/50 rounded-lg p-4">
  <MessageContent className="text-sm">{content}</MessageContent>
</Message>

<Reasoning className="border-l-2 border-blue-500 pl-4">
  <ReasoningTrigger className="text-blue-600" />
  <ReasoningContent className="text-muted-foreground" />
</Reasoning>

Integration with AI SDK

These components work seamlessly with Vercel AI SDK hooks:

import { useChat } from 'ai/react';
import { useCompletion } from 'ai/react';
import { useAssistant } from 'ai/react';

// useChat for conversational interfaces
const { messages, input, handleSubmit } = useChat();

// useCompletion for single completions
const { completion, complete } = useCompletion();

// useAssistant for OpenAI Assistants
const { messages, submitMessage } = useAssistant();

Reference

See references/component-api.md for complete props documentation.

Weekly Installs
2
Installed on
opencode2
claude-code2
windsurf1
cursor1
codex1
antigravity1