Join our Discord Community

React AI Loader

Spinning animation for loading states. Build responsive loading indicators with React, Next.js, and TypeScript, featuring customizable size and styling for shadcn/ui applications.

Trying to implement AI Elements?

Join our Discord community for help from other developers.


Loading spinners for AI operations in conversational AI applications. Because users need to know something's happening during the 10-30 seconds it takes to generate responses in React applications.

Spinning loader animation

Customizable size with smooth CSS animation:

Loading component...

Simple animated spinner that scales to different sizes and inherits colors from your theme in TypeScript components. Uses CSS animations so it doesn't kill performance in JavaScript frameworks.

Installation

npx shadcn@latest add https://www.shadcn.io/registry/ai.json
npx shadcn@latest add https://www.shadcn.io/registry/ai.json
pnpm dlx shadcn@latest add https://www.shadcn.io/registry/ai.json
bunx shadcn@latest add https://www.shadcn.io/registry/ai.json

Usage

import { Loader } from '@/components/ai/loader';

<Loader />
<Loader size={24} />
<Loader className="text-blue-500" />

Why not just disable the button?

Disabled buttons tell users they can't do something, but not why in React applications. A loading spinner communicates that work is happening and will finish eventually.

AI operations take 10-30 seconds regularly in Next.js projects. Without feedback, users refresh the page or click submit again. Both break your app.

Usage with Vercel AI SDK

Show loading states during Vercel AI SDK operations using status from useChat in React applications:

"use client";

import {
  Conversation,
  ConversationContent,
} from "@/components/ai/conversation";
import { Message, MessageContent } from "@/components/ai/message";
import {
  PromptInput,
  PromptInputTextarea,
  PromptInputSubmit,
} from "@/components/ai/prompt-input";
import { Loader } from "@/components/ai/loader";
import { useChat } from "@ai-sdk/react";
import { useState } from "react";

export default function Chat() {
  const [input, setInput] = useState("");
  const { messages, append, status } = useChat();

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (input.trim()) {
      append({ role: "user", content: input });
      setInput("");
    }
  };

  return (
    <div className="flex flex-col h-full">
      <Conversation>
        <ConversationContent>
          {messages.map((message) => (
            <Message from={message.role} key={message.id}>
              <MessageContent>{message.content}</MessageContent>
            </Message>
          ))}
          {status === "loading" && (
            <div className="flex items-center gap-2 p-4">
              <Loader size={20} />
              <span className="text-muted-foreground text-sm">Thinking...</span>
            </div>
          )}
        </ConversationContent>
      </Conversation>

      <PromptInput onSubmit={handleSubmit}>
        <PromptInputTextarea
          value={input}
          placeholder="Ask something..."
          onChange={(e) => setInput(e.currentTarget.value)}
        />
        <PromptInputSubmit status={status} disabled={!input.trim()} />
      </PromptInput>
    </div>
  );
}

Backend route for streaming:

// app/api/chat/route.ts
import { streamText, convertToModelMessages } from "ai";

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = streamText({
    model: "openai/gpt-4o",
    messages: convertToModelMessages(messages),
  });

  return result.toUIMessageStreamResponse();
}

Examples

Custom styling variations

Different colors, animation speeds, and background contexts:

Loading component...

Features

  • CSS animations that don't block the main thread in React applications
  • Scales to any size without looking pixelated in Next.js projects
  • Inherits text color from parent (use text-primary, text-muted, etc.) with TypeScript support
  • Proper accessibility with role="status"
  • Works with any Vercel AI SDK hook status and AI chat applications
  • Free open source component designed for conversational AI operations in JavaScript frameworks

API Reference

Loader

Spinning animation component for loading states.

PropTypeDefaultDescription
sizenumber16Width and height in pixels
classNamestring-Additional CSS classes
...propsHTMLAttributes<HTMLDivElement>-Standard div attributes

Keyboard interactions

KeyDescription
TabSkip over loader (not focusable)

Loading spinner gotchas

Don't show loaders for fast operations: Sub-200ms operations should complete without spinners in React applications. They flash and feel broken.

Size for context: 16px for inline text, 24px for buttons, 32px+ for page-level loading in Next.js projects. Too small looks weak, too big dominates.

JavaScript animations kill performance: Use CSS transforms and opacity in TypeScript components. Avoid updating DOM properties in animation loops.

Generic "Loading..." is useless: Say "Generating response..." or "Processing image..." so users know what's actually happening in React applications.

Forgetting mobile considerations: Spinners need to be readable on small screens. Test at actual mobile sizes in JavaScript implementations.

Integration with other components

Works great with PromptInput for input states in React applications. Drop into Message for typing indicators in Next.js projects. Combine with Conversation for chat loading states. This free open source component integrates seamlessly with modern JavaScript frameworks.

Questions developers actually ask