File: loader.md | Updated: 11/15/2025
Slash Forward
Docs Cookbook Providers Playground AI ElementsAI ElementsLeft sparkleRight sparkle AI GatewayGateway
Search...⌘KFeedback GitHub Vercel LogoSign in with Vercel
Utilities
A spinning loader component for indicating loading states in AI applications.
The Loader component provides a spinning animation to indicate loading states in your AI applications. It includes both a customizable wrapper component and the underlying icon for flexible usage.
Preview
Code
Loader
AI Elements
shadcn CLI
Manual
npx ai-elements@latest add loader
Build a simple chat app that displays a loader before the response starts streaming by using status === "submitted".
Add the following component to your frontend:
app/page.tsx
'use client';
import {
Conversation,
ConversationContent,
ConversationScrollButton,
} from '@/components/ai-elements/conversation';
import { Message, MessageContent } from '@/components/ai-elements/message';
import {
Input,
PromptInputTextarea,
PromptInputSubmit,
} from '@/components/ai-elements/prompt-input';
import { Loader } from '@/components/ai-elements/loader';
import { useState } from 'react';
import { useChat } from '@ai-sdk/react';
const LoaderDemo = () => {
const [input, setInput] = useState('');
const { messages, sendMessage, status } = useChat();
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (input.trim()) {
sendMessage({ text: input });
setInput('');
}
};
return (
<div className="max-w-4xl mx-auto p-6 relative size-full rounded-lg border h-[600px]">
<div className="flex flex-col h-full">
<Conversation>
<ConversationContent>
{messages.map((message) => (
<Message from={message.role} key={message.id}>
<MessageContent>
{message.parts.map((part, i) => {
switch (part.type) {
case 'text':
return (
<div key={`${message.id}-${i}`}>{part.text}</div>
);
default:
return null;
}
})}
</MessageContent>
</Message>
))}
{status === 'submitted' && <Loader />}
</ConversationContent>
<ConversationScrollButton />
</Conversation>
<Input
onSubmit={handleSubmit}
className="mt-4 w-full max-w-2xl mx-auto relative"
>
<PromptInputTextarea
value={input}
placeholder="Say something..."
onChange={(e) => setInput(e.currentTarget.value)}
className="pr-12"
/>
<PromptInputSubmit
status={status === 'streaming' ? 'streaming' : 'ready'}
disabled={!input.trim()}
className="absolute bottom-1 right-1"
/>
</Input>
</div>
</div>
);
};
export default LoaderDemo;
Add the following route to your backend:
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: 'openai/gpt-4o',
messages: convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
size propanimate-spin animation with proper centeringAILoader wrapper and LoaderIcon for flexible usagecurrentColor for proper theme integrationPreview
Code
Small (16px)
Loader
Medium (24px)
Loader
Large (32px)
Loader
Extra Large (48px)
Loader
Preview
Code
Blue
Loader
Green
Loader
Purple
Loader
Orange
Loader
Slow Animation
Loader
Fast Animation
Loader
With Background
Loader
Dark Background
Loader
<Loader />Prop
Type
size?number
...props?React.HTMLAttributes<HTMLDivElement>
Image
Displays AI-generated images from the AI SDK.
On this page
Installation
Usage with AI SDK
Features
Examples
Different Sizes
Custom Styling
Props
<Loader />
GitHubEdit this page on GitHub Scroll to topCopy pageOpen in chat