Copilot UI

Pre-built chat components and styling setup

The SDK provides production-ready chat UI components that work out of the box. This page covers the base setup and available themes.


Quick Setup

import { CopilotChat } from "@yourgpt/copilot-sdk/ui";

export default function App() {
  return <CopilotChat className="h-full" />;
}

Configure Tailwind

The SDK uses Tailwind CSS utility classes. Add the SDK source path to your CSS based on your project structure:

CSS file location@source path
app/globals.css@source "../node_modules/@yourgpt/copilot-sdk/dist/**/*.{js,ts,jsx,tsx}";
src/app/globals.css@source "../../node_modules/@yourgpt/copilot-sdk/dist/**/*.{js,ts,jsx,tsx}";
globals.css (root)@source "node_modules/@yourgpt/copilot-sdk/dist/**/*.{js,ts,jsx,tsx}";

Styling Options

Choose the approach that fits your project:

If you have shadcn/ui configured, just add the SDK source path. The SDK works automatically with your existing CSS variables.

app/globals.css
@import "tailwindcss";

@source "../node_modules/@yourgpt/copilot-sdk/dist/**/*.{js,ts,jsx,tsx}";

@custom-variant dark (&:is(.dark *));

/* Your existing shadcn/ui @theme and variables... */
import { CopilotChat } from "@yourgpt/copilot-sdk/ui";

// Works automatically with your shadcn/ui variables
<CopilotChat />

If you don't have shadcn/ui, import the SDK's base styles and add the theme mapping:

1. Import base styles:

import "@yourgpt/copilot-sdk/ui/styles.css";
import { CopilotChat } from "@yourgpt/copilot-sdk/ui";

<CopilotChat />

2. Add Tailwind config:

app/globals.css
@import "tailwindcss";

@source "../node_modules/@yourgpt/copilot-sdk/dist/**/*.{js,ts,jsx,tsx}";

@custom-variant dark (&:is(.dark *));

/* Map CSS variables to Tailwind theme (required for Tailwind v4) */
@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-popover: var(--popover);
  --color-popover-foreground: var(--popover-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-accent: var(--accent);
  --color-accent-foreground: var(--accent-foreground);
  --color-destructive: var(--destructive);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);
}

@layer base {
  * {
    @apply border-border;
  }
  body {
    @apply bg-background text-foreground;
  }
}

The @theme inline block is required for Tailwind v4 to map CSS variables to utility classes like bg-background.

Add the SDK package to your Tailwind config content paths:

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './app/**/*.{js,ts,jsx,tsx,mdx}',
    './components/**/*.{js,ts,jsx,tsx,mdx}',
    './node_modules/@yourgpt/copilot-sdk/dist/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};

Then import base styles:

import "@yourgpt/copilot-sdk/ui/styles.css";
import { CopilotChat } from "@yourgpt/copilot-sdk/ui";

<CopilotChat />

Theme Presets

The SDK includes 8 pre-built themes. Import a theme CSS file and wrap your component:

import "@yourgpt/copilot-sdk/ui/styles.css";
import "@yourgpt/copilot-sdk/ui/themes/claude.css";
import { CopilotChat } from "@yourgpt/copilot-sdk/ui";

<div className="csdk-theme-claude">
  <CopilotChat />
</div>

Available Themes

ThemeImportClassStyle
Claudethemes/claude.csscsdk-theme-claudeWarm terra cotta, earthy
Vercelthemes/vercel.csscsdk-theme-vercelMonochrome, minimal
Supabasethemes/supabase.csscsdk-theme-supabaseGreen, developer-focused
Twitterthemes/twitter.csscsdk-theme-twitterBold blue, rounded
Linearthemes/linear.csscsdk-theme-linearPurple, sophisticated
PostHogthemes/posthog.csscsdk-theme-posthogYellow NeoBrutalism
Catppuccinthemes/catppuccin.csscsdk-theme-catppuccinPastel community theme
Modernthemes/modern-minimal.csscsdk-theme-modernClean tech blue

Dark Mode

Themes automatically support dark mode when the dark class is on an ancestor element:

// Works with next-themes, etc.
<html className="dark">
  <body>
    <div className="csdk-theme-claude">
      <CopilotChat />
    </div>
  </body>
</html>

Loader Variants

Customize the loading indicator shown when AI is generating a response:

<CopilotChat loaderVariant="typing" />

Available Variants

VariantDescription
typingTyping indicator dots (default)
dotsBouncing dots
waveWave animation
terminalTerminal cursor blink
text-blinkBlinking "Thinking" text
text-shimmerShimmer effect "Thinking" text
loading-dots"Thinking..." with animated dots

Text-based Loaders

The text-based variants (text-blink, text-shimmer, loading-dots) display "Thinking" text with animations:

// Blinking text
<CopilotChat loaderVariant="text-blink" />

// Shimmer effect
<CopilotChat loaderVariant="text-shimmer" />

// "Thinking..." with animated dots
<CopilotChat loaderVariant="loading-dots" />

Avatars

Customize the avatars shown next to messages:

Basic Usage

<CopilotChat
  assistantAvatar={{
    src: "/bot-avatar.png",
    fallback: "AI"
  }}
  userAvatar={{
    src: "/user-avatar.png",
    fallback: "U"
  }}
  showUserAvatar  // Enable user avatar display
/>

Custom Avatar Component

Pass a custom React component for full control:

<CopilotChat
  assistantAvatar={{
    component: (
      <img
        src="/custom-bot.svg"
        className="size-full rounded-full"
      />
    )
  }}
  userAvatar={{
    component: <MyUserAvatar />
  }}
  showUserAvatar
/>

Avatar Props

PropTypeDescription
srcstringImage URL
fallbackstringText shown while image loads or if it fails
componentReactNodeCustom component (overrides src/fallback)

User avatars are hidden by default. Set showUserAvatar to display them.


Pre-built Components

The SDK exports these ready-to-use components:

ComponentDescription
CopilotChatFull chat interface with messages, input, and history
CopilotChatCompoundComposable chat with slots for header, footer, etc.
MessageSingle message display
PromptInputText input with send button
CodeBlockSyntax-highlighted code display
ModelSelectorDropdown to switch AI models
ThreadPickerConversation history selector

Basic Usage

import {
  CopilotChat,
  CopilotChatCompound,
  Message,
  PromptInput
} from "@yourgpt/copilot-sdk/ui";

// Simple - use CopilotChat
<CopilotChat />

// Advanced - use compound components
<CopilotChatCompound>
  <CopilotChatCompound.Header>
    <h1>My Assistant</h1>
  </CopilotChatCompound.Header>
  <CopilotChatCompound.Messages />
  <CopilotChatCompound.Input />
</CopilotChatCompound>


Message Actions

Add floating copy, edit, feedback, and custom buttons to messages. Actions appear on hover below each message bubble.

<CopilotChat>
  <CopilotChat.MessageActions role="assistant">
    <CopilotChat.CopyAction />
    <CopilotChat.FeedbackAction
      onFeedback={(message, type) => sendFeedback({ messageId: message.id, type })}
    />
  </CopilotChat.MessageActions>

  <CopilotChat.MessageActions role="user">
    <CopilotChat.EditAction />
  </CopilotChat.MessageActions>
</CopilotChat>
ComponentDescription
CopilotChat.MessageActionsRegisters actions for a role (user or assistant)
CopilotChat.CopyActionCopy message to clipboard
CopilotChat.EditActionInline edit for user messages
CopilotChat.FeedbackActionThumbs up / down
CopilotChat.ActionFully custom action button
// Custom action
<CopilotChat.MessageActions role="assistant">
  <CopilotChat.CopyAction />
  <CopilotChat.Action
    icon={<ShareIcon />}
    tooltip="Share"
    onClick={({ message }) => share(message.content)}
  />
</CopilotChat.MessageActions>

// Conditional — hide based on message content
<CopilotChat.Action
  icon={<FlagIcon />}
  tooltip="Report"
  hidden={({ message }) => !message.content}
  onClick={({ message }) => report(message.id)}
/>

Props

// MessageActions
role: "user" | "assistant"

// CopyAction / EditAction
tooltip?: string
className?: string

// FeedbackAction
onFeedback?: (message: ChatMessage, type: "helpful" | "not-helpful") => void
tooltip?: string

// Action (custom)
icon: ReactNode
tooltip: string
onClick: (props: { message: ChatMessage }) => void
hidden?: boolean | ((props: { message: ChatMessage }) => boolean)

If no MessageActions children are declared, the chat UI is identical to before — purely additive.


Markdown Rendering

Existing applications keep sanitized HTML rendering by default. To display raw HTML snippets as literal text, opt in:

<CopilotChat markdown={{ rawHtml: "literal" }} />

markdown.rawHtml accepts "render" (the default) or "literal". Both modes retain normal markdown, fenced code, tables and links. Literal mode also displays tags that the sanitizer otherwise removes, such as an unfenced <script> snippet. The setting applies to user and assistant messages, including Chat.MessageList. Pass rawHtml directly to Markdown or MessageContent for a single message.


Next Steps

On this page