Dosu LogoDosu Logo
Ask
Join our Discord
assistant-ui's SpacePublic
assistant-ui
Documentsassistant-ui's Space
chatgpt
chatgpt
Type
External
Status
Published
Created
Mar 17, 2026
Updated
Aug 18, 2026
Updated by
Dosu Bot
Source
apps/docs/content/examples/chatgpt.mdx

Overview#

The ChatGPT Clone demonstrates how to customize assistant-ui to match OpenAI's ChatGPT interface. This version mirrors the current chatgpt.com layout: a centered welcome composer, tooltipped attachment/dictation/voice controls, high-contrast user bubbles with Copy + Edit actions, and an always-visible assistant action bar with thumbs, share, speak, reload, and more.

Features#

  • Theme-Aware: White light mode (#ffffff) and black dark mode (#000000) with ChatGPT-style #212121 composer surfaces
  • Centered Empty State: "Where should we begin?" heading + composer rendered together above the viewport center
  • Tooltipped Composer Controls: Add attachment, Dictate, and voice-mode buttons use ChatGPT's circular controls and hover tooltips
  • Four-State Primary Action: Cancel (running), StopDictation (recording), Send (typing), Dictate + voice mode (idle)
  • Assistant Action Bar: Always visible — Copy, Good response, Bad response, Read aloud, Share, Regenerate, More
  • User Bubble: Right-aligned high-contrast bubble with Copy + Edit actions below on hover
  • Sticky Footer: Composer + "ChatGPT can make mistakes" disclaimer at the bottom of the chat

Quick Start#

npx assistant-ui add thread

Code#

The ChatGPT clone splits into an EmptyState and a sticky chat layout. The same composer shell is shared by both:

import {
  AuiIf,
  ThreadPrimitive,
  ComposerPrimitive,
  ActionBarPrimitive,
} from "@assistant-ui/react";
import { PlusIcon } from "lucide-react";
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";

export const ChatGPT = () => (
  <ThreadPrimitive.Root className="bg-white text-[#0d0d0d] dark:bg-black dark:text-[#ececec]">
    <AuiIf condition={(s) => s.thread.isEmpty}>
      <EmptyState />
    </AuiIf>
    <AuiIf condition={(s) => !s.thread.isEmpty}>
      <ThreadPrimitive.Viewport>
        <ThreadPrimitive.Messages />
        <ThreadPrimitive.ViewportFooter className="sticky bottom-0">
          <Composer placeholder="Ask anything" />
          <p>ChatGPT can make mistakes. Check important info.</p>
        </ThreadPrimitive.ViewportFooter>
      </ThreadPrimitive.Viewport>
    </AuiIf>
  </ThreadPrimitive.Root>
);

const Composer = ({ placeholder }: { placeholder: string }) => (
  <ComposerPrimitive.Root className="rounded-[28px] border border-[#e5e5e5] bg-white dark:border-transparent dark:bg-[#212121]">
    <div className="flex items-end gap-1">
      <ComposerPrimitive.AddAttachment asChild>
        <TooltipIconButton tooltip="Add photos & files" aria-label="Add attachment">
          <PlusIcon />
        </TooltipIconButton>
      </ComposerPrimitive.AddAttachment>
      <ComposerPrimitive.Input autoFocus rows={1} placeholder={placeholder} />
      <PrimaryAction />
    </div>
  </ComposerPrimitive.Root>
);

Four-State Primary Action#

<AuiIf condition={(s) => s.thread.isRunning}>
  <ComposerPrimitive.Cancel />
</AuiIf>
<AuiIf condition={(s) => !s.thread.isRunning && s.composer.dictation != null}>
  <ComposerPrimitive.StopDictation />
</AuiIf>
<AuiIf
  condition={(s) =>
    !s.thread.isRunning && s.composer.dictation == null && !s.composer.isEmpty
  }
  <ComposerPrimitive.Send />
</AuiIf>
<AuiIf
  condition={(s) =>
    !s.thread.isRunning && s.composer.dictation == null && s.composer.isEmpty
  }
  <ComposerPrimitive.Dictate asChild>
    <TooltipIconButton tooltip="Dictate" aria-label="Dictate">
      <Mic />
    </TooltipIconButton>
  </ComposerPrimitive.Dictate>
  <TooltipIconButton
    tooltip="Use voice mode"
    aria-hidden="true"
    tabIndex={-1}
    className="bg-[#0d0d0d] text-white dark:bg-white dark:text-black"
    <AudioLines />
  </TooltipIconButton>
</AuiIf>

The conditions are mutually exclusive in priority order (Cancel > StopDictation > Send > Dictate/voice mode) so dictation can be paused even when transcribed text is in the composer.

User Bubble and Actions#

<MessagePrimitive.Root className="flex flex-col items-end gap-1">
  <div className="max-w-[70%] rounded-[22px] bg-[#0d0d0d] px-4 py-2.5 text-white dark:bg-[#ececec] dark:text-[#0d0d0d]">
    <MessagePrimitive.Parts />
  </div>

  <ActionBarPrimitive.Root autohide="always">
    <ActionBarPrimitive.Copy asChild>
      <TooltipIconButton tooltip="Copy" />
    </ActionBarPrimitive.Copy>
    <ActionBarPrimitive.Edit asChild>
      <TooltipIconButton tooltip="Edit" />
    </ActionBarPrimitive.Edit>
  </ActionBarPrimitive.Root>
</MessagePrimitive.Root>

Color Palette#

ElementLightDark
Background#ffffff#000000
Composer surface#ffffff#212121
Composer border / edge#e5e5e5transparent + inset white edge
Primary text#0d0d0d#ececec
Muted text#5d5d5d#afafaf
User bubble#0d0d0d (white text)#ececec (#0d0d0d text)
Action icon#5d5d5d#cdcdcd
Icon hover backgroundblack at 7%white at 15%
Send / voice button#0d0d0d (white icon)#ffffff (black icon)

Styling Details#

  • Composer: rounded-[28px] with a thin light-mode border, dark #212121 surface, and an inset dark-mode edge
  • Empty Layout: 24px/400 heading + composer raised above center; no avatar
  • Composer Buttons: 36px circular controls with hover tooltips and background-only hover states
  • Assistant Action Bar: 32px controls, 8px radius, zero gap, background-only hover, and tooltips on every action
  • User Bubble: rounded-[22px], 70% max width, high-contrast theme colors, Copy + Edit actions below on hover

Source#

Documents
AG-UI Message History Management
AGENTS
AGENTS
ai-sdk-assistant-ui
CHANGELOG
CHANGELOG
CHANGELOG
README
AG-UI Streaming State Management
AGENTS
ai-sdk-assistant-ui
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
index
README
README
AI SDK Integration
AGENTS
ai-sdk
ai-sdk
assistant-runtime-provider
CHANGELOG
CHANGELOG
form-demo
hooks
index
index
migration
migration
overview
part-2
README
README
README
README
README
README
SKILL
SPEC_AssistantFrame
v4-legacy
v5-legacy
AI SDK Version Compatibility
migration
migration
v4-legacy
v5-legacy
Audio Content Handling
CHANGELOG
CHANGELOG
README
Bedrock Tool Call Streaming
CHANGELOG
Chat History Loading
Chat Transport
AGENTS
ai-sdk
ai-sdk-assistant-ui
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
child-scopes
expo
external-store
form-demo
hooks
index
index
migration
overview
pick-a-runtime
primitives
README
README
README
README
README
README
README
SKILL
SPEC_AssistantFrame
stockbroker
Code Block Rendering
index
markdown
Composer Attachment Handling
attachment
CHANGELOG
CHANGELOG
CHANGELOG
composer
form-demo
index
migration
overview
part-2
perplexity
primitives
primitives
README
README
SKILL
Data Stream Decoding
README
External History Adapter
External Store Adapter
adapters
ai-sdk
external-store
README
sibling-scopes
File Message Part Handling
file
LangChain Message Processing
AGENTS
CHANGELOG
CHANGELOG
CHANGELOG
external-store
migration
part-2
SKILL
LangGraph File Attachments
AGENTS
attachment
CHANGELOG
CHANGELOG
CHANGELOG
external-store
index
primitives
README
LangGraph Runtime API
AGENTS
ai-sdk-assistant-ui
CHANGELOG
CHANGELOG
CHANGELOG
expo
hooks
hooks
index
index
langgraph
migration
overview
pick-a-runtime
README
README
SKILL
Math Delimiter Preprocessing
CHANGELOG
Model Context Provider System
ai-sdk
hooks
model-selector
README
sibling-scopes
Plain Text Stream Encoder
Popover and Command UI Components
chatgpt
claude
grok
modal
model-selector
perplexity
README
SKILL
React Store Notification Manager
quickstart
README
SPEC
why-store
React Version Compatibility
Reasoning Disclosure State Machine
reasoning
SKILL
Remote Thread List Runtime
AGENTS
ai-sdk
hooks
hooks
overview
README
README
README
Resumable Streams
AGENTS
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
child-scopes
Run Cancellation and Abort Signal Propagation
AGENTS
CHANGELOG
CHANGELOG
README
README
Safari Browser Compatibility
CHANGELOG
index
migration
SPEC_AssistantFrame
Shimmer Text Animation
index
StreamdownTextPrimitive
CHANGELOG
Tap React Hook Lifecycle Management
CHANGELOG
child-scopes
methods
quickstart
README
README
why-store
Thread List Runtime API
adapters
ai-sdk
hooks
hooks
langgraph
README
rendering-lists
thread-list
Thread List UI Components
ai-sdk
langgraph
primitives
primitives
rendering-lists
thread-list
Thread Switch Stability
AGENTS
CHANGELOG
CHANGELOG
CHANGELOG
index
primitives
Tool Approval Gates
CHANGELOG
part-3
stockbroker
tool-fallback
Tool Approval Permission Model
CHANGELOG
CHANGELOG
part-3
README
SPEC_AssistantFrame
stockbroker
Tool Call Stream Lifecycle
CHANGELOG
tool-fallback
Top-Anchor Reserve
URL-Based Thread Routing
langgraph
README
SKILL
thread-list
Viewport Auto-Scroll
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CHANGELOG
CLAUDE
CODE_OF_CONDUCT
CONTRIBUTING
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README
README_LANGGRAPH
SECURITY
SPEC_ModelContextRegistry
action-bar
action-bar-more
adapters
api-reference
artifacts
assistant-if
assistant-modal
assistant-modal
assistant-runtime
assistant-sidebar
attachment
attachment-runtime
authorization
branch-picker
composer-runtime
composition
context-display
custom-backend
custom-backend
error
events
heat-graph
image
index
index
index
index
index
index
index
index
introduction
mem0
mermaid
message
message-part
message-part-runtime
message-runtime
message-timing
meta
part-1
part-grouping
quote
scopes
scrollbar
selection-toolbar
simplify-review
sources
state
streamdown
suggestion
syntax-highlighting
thread
thread
thread-list
thread-list-item
thread-list-item-more
thread-list-item-runtime
thread-list-runtime
thread-runtime
tool-group
tw-shimmer