Learn-skills.dev ai-sdk-elements
git clone https://github.com/NeverSight/learn-skills.dev
T=$(mktemp -d) && git clone --depth=1 https://github.com/NeverSight/learn-skills.dev "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/skills-md/aaronbakerdev/knearme-platform/ai-sdk-elements" ~/.claude/skills/neversight-learn-skills-dev-ai-sdk-elements && rm -rf "$T"
data/skills-md/aaronbakerdev/knearme-platform/ai-sdk-elements/SKILL.mdAI 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.