import { Claude } from "@/components/examples/claude";
Overview#
The Claude Clone demonstrates how to customize assistant-ui to match Anthropic's Claude interface. The design leans on Claude's signature warm cream background, serif typography, and a deliberately minimal chrome — no shadows, no avatars, just a thin border on the composer and bubbles that fade into the page.
Features#
- Warm Cream Background:
#F0ECE0light,#2b2a27dark — a warmer Anthropic-style cream - Serif Throughout:
font-serifon every surface for the editorial feel - Sparkle Heading: Centered "How can I help you today?" with the orange
#c96442Sparkle icon - Borderless Composer: Just
border-[#E5E0D6]and no shadow — matches claude.ai's stripped-down look - Functional Model Picker: Sonnet 4.5 / Opus 4.7 / Haiku 4.5 dropdown with "More options"
- Mode Tabs: Write / Learn / Code / From Drive / From Calendar —
rounded-lgchips with thin borders - Hover-only Action Bars: User Edit/Copy and Assistant Copy/👍/👎/Reload only appear on hover
- Four-State Primary Action: Cancel, StopDictation, Send, Dictate (orange
#c96442accent)
Quick Start#
npx assistant-ui add thread
Code#
The empty state centers the heading + composer + mode tabs together. The chat state uses a sticky composer with a fade-out gradient over the cream background:
import {
AuiIf,
ThreadPrimitive,
ComposerPrimitive,
MessagePrimitive,
ActionBarPrimitive,
} from "@assistant-ui/react";
export const Claude = () => (
<ThreadPrimitive.Root className="bg-[#F0ECE0] font-serif dark:bg-[#2b2a27]">
<AuiIf condition={(s) => s.thread.isEmpty}>
<EmptyState />
</AuiIf>
<AuiIf condition={(s) => !s.thread.isEmpty}>
<ThreadPrimitive.Viewport>
<ThreadPrimitive.Messages>
{() => <ChatMessage />}
</ThreadPrimitive.Messages>
<ThreadPrimitive.ViewportFooter className="sticky bottom-0">
<Composer />
<p>Claude can make mistakes. Please double-check responses.</p>
</ThreadPrimitive.ViewportFooter>
</ThreadPrimitive.Viewport>
</AuiIf>
</ThreadPrimitive.Root>
);
const EmptyState = () => (
<div className="flex grow flex-col items-center justify-center">
<h1 className="flex items-center gap-3 font-serif text-3xl">
<Sparkle className="fill-[#c96442] text-[#c96442]" />
How can I help you today?
</h1>
<Composer />
<ModeTabs />
</div>
);
const Composer = () => (
<ComposerPrimitive.Root className="rounded-2xl border border-[#E5E0D6] bg-white px-3.5 pt-3 pb-2.5 dark:border-[#3d3a35] dark:bg-[#1f1e1b]">
<ComposerPrimitive.Input rows={1} placeholder="How can I help you today?" />
<div className="flex items-center gap-2">
<ComposerPrimitive.AddAttachment />
<div className="ml-auto flex items-center gap-1">
<ModelPicker />
<PrimaryAction />
</div>
</div>
</ComposerPrimitive.Root>
);
Hover-only Action Bars#
Both user and assistant action bars use opacity + group-hover to stay out of the way:
<MessagePrimitive.Root className="group/message">
<div className="rounded-2xl bg-[#E5E0D6] px-4 py-2.5">
<MessagePrimitive.Parts components={{ Text: MarkdownText }} />
</div>
<ActionBarPrimitive.Root
hideWhenRunning
autohide="not-last"
className="opacity-0 transition-opacity group-hover/message:opacity-100"
<ActionBarPrimitive.Edit />
<ActionBarPrimitive.Copy />
</ActionBarPrimitive.Root>
</MessagePrimitive.Root>
Color Palette#
| Element | Light | Dark |
|---|---|---|
| Background | #F0ECE0 | #2b2a27 |
| Composer surface | white | #1f1e1b |
| Composer border | #E5E0D6 | #3d3a35 |
| User bubble | #E5E0D6 | #393937 |
| Primary text | #1a1a18 | #eee |
| Muted text | #5b5950 | #a3a098 |
| Primary action (orange) | #c96442 | #c96442 |
Styling Details#
- Typography:
font-serifeverywhere; assistant message usesleading-[1.65rem]for a calm reading rhythm - No Shadows: Composer relies on
border-[#E5E0D6]only — claude.ai's signature flat surface - User Bubble:
rounded-2xl bg-[#E5E0D6] max-w-[80%]right-aligned - Assistant Message: full-width plain serif, no bubble, no avatar — text sits on the cream background directly
- Mode Tabs:
rounded-lg border border-[#E5E0D6] bg-transparentso they blend into the cream