Skip to main content

Quick Start

This guide will walk you through adding your first Gaia UI component to a Next.js application. We’ll build a simple chat interface using the Composer and Message Bubble components.

What We’ll Build

By the end of this tutorial, you’ll have a working chat interface with:
  • A message input with file upload support
  • Message bubbles that look like iMessage
  • Slash commands for AI tools
  • Dark mode support

Step-by-Step Tutorial

1

Create a Next.js project

If you don’t already have a Next.js project, create one:
npx create-next-app@latest my-ai-chat
cd my-ai-chat
When prompted:
  • Choose Yes for TypeScript
  • Choose Yes for Tailwind CSS
  • Choose Yes for App Router
2

Install shadcn/ui base components

Initialize shadcn/ui in your project:
npx shadcn@latest init
When prompted, choose the New York style for consistency with Gaia UI.Then install the base components we’ll need:
npx shadcn@latest add button avatar
3

Add Gaia UI components

Now let’s add the Composer and Message Bubble components:
npx @heygaia/ui add composer message-bubble
This will install the components and all their dependencies including:
  • file-preview - For file uploads
  • slash-command-dropdown - For AI tool selection
  • icons - Hugeicons icon set
4

Create the chat interface

Create a new file app/page.tsx with the following code:
"use client";

import { useState } from "react";
import { Composer } from "@/components/ui/composer";
import { MessageBubble, ChatMessage } from "@/components/ui/message-bubble";

interface Message {
  id: string;
  content: string;
  role: "user" | "assistant";
  timestamp: string;
}

export default function Home() {
  const [messages, setMessages] = useState<Message[]>([
    {
      id: "1",
      content: "Hello! I'm your AI assistant. How can I help you today?",
      role: "assistant",
      timestamp: new Date().toLocaleTimeString([], {
        hour: "2-digit",
        minute: "2-digit",
      }),
    },
  ]);

  const handleSubmit = (message: string) => {
    if (!message.trim()) return;

    // Add user message
    const userMessage: Message = {
      id: Date.now().toString(),
      content: message,
      role: "user",
      timestamp: new Date().toLocaleTimeString([], {
        hour: "2-digit",
        minute: "2-digit",
      }),
    };

    setMessages((prev) => [...prev, userMessage]);

    // Simulate AI response
    setTimeout(() => {
      const aiMessage: Message = {
        id: (Date.now() + 1).toString(),
        content: `I received your message: "${message}"`,
        role: "assistant",
        timestamp: new Date().toLocaleTimeString([], {
          hour: "2-digit",
          minute: "2-digit",
        }),
      };
      setMessages((prev) => [...prev, aiMessage]);
    }, 1000);
  };

  return (
    <main className="flex min-h-screen flex-col">
      {/* Header */}
      <header className="border-b">
        <div className="container mx-auto px-4 py-4">
          <h1 className="text-2xl font-semibold">AI Chat Assistant</h1>
          <p className="text-sm text-muted-foreground">
            Powered by Gaia UI
          </p>
        </div>
      </header>

      {/* Chat Messages */}
      <div className="flex-1 overflow-y-auto">
        <div className="container mx-auto px-4 py-6 space-y-4">
          {messages.map((msg) => (
            <div
              key={msg.id}
              className={`flex ${
                msg.role === "user" ? "justify-end" : "justify-start"
              }`}
            >
              <div className="max-w-[80%]">
                <MessageBubble
                  message={msg.content}
                  variant={msg.role === "user" ? "sent" : "received"}
                />
                <p className="text-xs text-muted-foreground mt-1 px-2">
                  {msg.timestamp}
                </p>
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* Message Input */}
      <div className="border-t">
        <div className="container mx-auto px-4 py-4">
          <Composer
            placeholder="Type a message or use / for commands..."
            onSubmit={handleSubmit}
            showToolsButton
            tools={[
              {
                id: "search",
                name: "Search",
                description: "Search the web for information",
              },
              {
                id: "calculator",
                name: "Calculator",
                description: "Perform mathematical calculations",
              },
              {
                id: "weather",
                name: "Weather",
                description: "Get current weather information",
              },
            ]}
            onToolSelect={(tool) => {
              console.log("Tool selected:", tool);
            }}
          />
        </div>
      </div>
    </main>
  );
}
5

Run your app

Start the development server:
npm run dev
Open http://localhost:3000 in your browser to see your chat interface.
6

Try the features

Your chat interface now supports:
  • Type messages - Enter text and press Enter or click the send button
  • Slash commands - Type / to see available AI tools
  • File uploads - Click the plus button to attach files
  • Dark mode - Toggle your system theme to see dark mode in action

What’s Next?

Add More Components

Explore other Gaia UI components to enhance your chat interface:
npx @heygaia/ui add tool-calls-section weather-card file-dropzone

Customize Styling

All components accept a className prop for custom styling:
<MessageBubble
  message="Custom styled message"
  variant="received"
  className="bg-blue-100 dark:bg-blue-900"
/>

Add Real AI Integration

Connect the Composer to a real AI service like OpenAI, Anthropic, or your custom backend:
const handleSubmit = async (message: string) => {
  const response = await fetch("/api/chat", {
    method: "POST",
    body: JSON.stringify({ message }),
  });
  
  const data = await response.json();
  // Handle AI response
};

Display Tool Calls

Use the Tool Calls Section component to show AI tool usage:
import { ToolCallsSection } from "@/components/ui/tool-calls-section";

<ToolCallsSection
  tools={[
    {
      name: "web_search",
      status: "running",
      description: "Searching for latest AI news",
    },
  ]}
/>

Handle File Uploads

The Composer component already supports file uploads. Access them in the submit handler:
<Composer
  onSubmit={(message, files) => {
    console.log("Message:", message);
    console.log("Uploaded files:", files);
    // Process files...
  }}
/>

Learn More

  • Browse the Components tab - Explore the full component library
  • View source code - See how components are built
  • Join Discord - Get help from the community

Need Help?

If you run into issues:
  1. Check the installation guide for troubleshooting tips
  2. Search GitHub issues
  3. Ask in our Discord community
  4. Review component documentation for specific usage examples

Build docs developers (and LLMs) love