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.
@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:
@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:
/** @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
| Theme | Import | Class | Style |
|---|---|---|---|
| Claude | themes/claude.css | csdk-theme-claude | Warm terra cotta, earthy |
| Vercel | themes/vercel.css | csdk-theme-vercel | Monochrome, minimal |
| Supabase | themes/supabase.css | csdk-theme-supabase | Green, developer-focused |
themes/twitter.css | csdk-theme-twitter | Bold blue, rounded | |
| Linear | themes/linear.css | csdk-theme-linear | Purple, sophisticated |
| PostHog | themes/posthog.css | csdk-theme-posthog | Yellow NeoBrutalism |
| Catppuccin | themes/catppuccin.css | csdk-theme-catppuccin | Pastel community theme |
| Modern | themes/modern-minimal.css | csdk-theme-modern | Clean 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
| Variant | Description |
|---|---|
typing | Typing indicator dots (default) |
dots | Bouncing dots |
wave | Wave animation |
terminal | Terminal cursor blink |
text-blink | Blinking "Thinking" text |
text-shimmer | Shimmer 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
| Prop | Type | Description |
|---|---|---|
src | string | Image URL |
fallback | string | Text shown while image loads or if it fails |
component | ReactNode | Custom 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:
| Component | Description |
|---|---|
CopilotChat | Full chat interface with messages, input, and history |
CopilotChatCompound | Composable chat with slots for header, footer, etc. |
Message | Single message display |
PromptInput | Text input with send button |
CodeBlock | Syntax-highlighted code display |
ModelSelector | Dropdown to switch AI models |
ThreadPicker | Conversation 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>| Component | Description |
|---|---|
CopilotChat.MessageActions | Registers actions for a role (user or assistant) |
CopilotChat.CopyAction | Copy message to clipboard |
CopilotChat.EditAction | Inline edit for user messages |
CopilotChat.FeedbackAction | Thumbs up / down |
CopilotChat.Action | Fully 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
- Customizations - Create custom themes, CSS classes, branding
- Generative UI - Render custom components from AI
- Branching - Conversation branching and edit history