Arc
ComponentsBlocksDocsPricingTry the demo
Introduction
Installation
Theming
Motion
AI and MCP
Changelog
Metrics dashboard
KPI drilldownNew
Metric explorer
Revenue explorer
MRR waterfall
Cohort retention
Usage forecast
Journey flow
Connected scatterNew
Market terminalNew
Budget varianceNew
Small multiplesNew
Line replayNew
AI chatNew
AI composer
Agent runNew
SidebarPro4
Page header
Command palette
Notification center
Empty states
Login and sign up5
OTP input
Multi-step formPro
Settings page
Security settings
Billing overview
Usage billingNew
Team members
Invite peopleNew
Team directory
Roles and permissions
API keys
Webhooks
Integrations
Plan comparison
Pricing calculatorNewPro
Usage pricingPro
Cart drawerNewPro
Checkout summaryNewPro
Invoice studio
Wallet card
Product listingNew
Product detailNew
Inbox triage
Support conversation
Support widget
File upload
Media playerPro
Week calendarNew
Availability picker
Project board
Release readiness
Hero sectionNew
Hero signupNewPro
Scroll storyNewPro
Spotlight gridNewPro
Feature bentoNewPro
Comparison tableNew
Logo marquee
Studio perspectivesPro
Stats bandNew
Changelog feed
FAQ sectionNew
Contact sectionNew
Team showcasePro
Blog gridNew
Site headerNew
Site footerNew
CTA sectionNew
Newsletter signupNew
Revenue globe
Customer galaxy
Semantic zoom
Layout morph
What’s new80 new
BlocksAI chat

AI chatPro

A complete AI chat with streamed markdown answers, folding reasoning, tool chips, citations, and a model switcher.

Live block · sample data

When to use

  • A full page assistant with conversation history, model choice, and streamed answers.
  • Research or support assistants that show tool calls and cite sources inline.
  • Products that need regenerate, answer versions, and editable prompts out of the box.

When not to use

  • Use ai-composer when you only need the prompt input.
  • Use chat-thread for person to person messaging without model output.
  • Use support-widget for a small floating help chat.

Installation

Pro source and install commands unlock with a Pro plan.

Usage

Use this as a starting point and replace the sample data with your own.

example.tsx
1"use client";2 3import { AiChat } from "@/registry/blocks/ai-chat/ai-chat";4import type { ChatResponder } from "@/registry/blocks/ai-chat/ai-chat";5 6const respond: ChatResponder = async function* (request, signal) {7  const response = await fetch("/api/chat", {8    method: "POST",9    body: JSON.stringify({ messages: request.messages, model: request.model }),10    signal,11  });12  const reader = response.body!.pipeThrough(new TextDecoderStream()).getReader();13  while (true) {14    const { value, done } = await reader.read();15    if (done) break;16    yield { type: "text", text: value };17  }18};19 20export function Assistant() {21  return (22    <AiChat23      respond={respond}24      notice={null}25      models={[{ id: "default", name: "Default", description: "Balanced for everyday work" }]}26      defaultModel="default"27      defaultConversations={[]}28      user={{ name: "Ava Mitchell", detail: "Pro plan" }}29    />30  );31}
Built fromMotion

API reference

5 parts. The first is the root.

AiChat

A full AI chat surface: a collapsible conversation list, streamed markdown answers, a reasoning panel, tool call chips, citations with source cards, regenerate with versions, editable prompts, a model switcher, image attachments, and a send button that becomes stop. Connect respond to your model. Also the default export.

PropTypeDefaultDescription
defaultConversationsChatConversation[]sampleConversationsInitial conversations. The block owns them afterwards.
onConversationsChange(conversations: ChatConversation[]) => void–Called after every change, including each streamed chunk. Not called on mount.
activeIdstring | null–Controlled open conversation id; null shows a new chat.
defaultActiveIdstring | nullnullOpen conversation on mount when uncontrolled.
onActiveChange(id: string | null) => void–Called when a conversation is opened or a new chat starts.
modelsChatModel[]sampleModelsOptions in the model switcher.
modelstring–Controlled model id.
defaultModelstring"atlas"Starting model id when uncontrolled.
onModelChange(id: string) => void–Called when a model is chosen.
sidebarOpenboolean–Controlled sidebar state on wide layouts.
defaultSidebarOpenbooleantrueStarting sidebar state on wide layouts.
onSidebarOpenChange(open: boolean) => void–Called when the wide sidebar opens or closes.
suggestionsChatSuggestion[]sampleSuggestionsPrompts offered on an empty chat.
respondChatRespondersampleResponder(request, signal) => AsyncIterable<ChatStreamEvent>. Streams thinking, tool, sources, and text events. The default plays scripted samples.
greetingstring"What are we working on?"Heading on an empty chat.
noticeReactNode"Sample responses"Small note in the header. Pass null to hide it.
user{ name: string; avatar?: string; detail?: string }{ name: "Emma Collins", avatar: "/media/people/emma-collins.jpg", detail: "Team plan" }Account shown at the bottom of the sidebar.
classNamestring–Extra class on the root.

ChatResponder

Exported type. (request: ChatRequest, signal: AbortSignal) => AsyncIterable<ChatStreamEvent>. ChatRequest is { conversationId, messages, prompt, attachments, model }. Stop aborts the signal.

No props.

ChatStreamEvent

Exported type. { type: "thinking"; text } appends reasoning, { type: "tool"; tool } adds or updates a ChatToolCall by id, { type: "sources"; sources } replaces the citation list, { type: "text"; text } appends answer markdown. The first tool or text event closes the thinking panel.

No props.

sampleResponder

The default scripted responder, exported for demos and tests. It honors the abort signal.

No props.

StreamText

Exported from ai-chat/markdown.tsx. Plain streamed text, such as reasoning: the same per-word fade as answers, without markdown blocks. Newlines become line breaks. The same file exports Markdown, parseBlocks, plainText, and CopyControl.

PropTypeDefaultDescription
textRequiredstring–Text so far.
streamingRequiredboolean–Animates newly arrived words while true.
reducedRequiredboolean–Pass the reduced motion preference; true renders words without the fade.
classNamestring–Class on the paragraph.

Keyboard interactions

Enter
Sends the message. Shift Enter adds a new line; IME composition is respected.
Escape
Stops generation from the composer, cancels a prompt edit, closes a source card, or closes the narrow drawer.
Arrow Down
On the model pill, opens the model list.
Arrow UporDown, HomeorEnd, EnterorSpace
Move through and choose in the model list; Escape closes it and returns focus to the pill.
Tab to a citation
Keyboard focus opens the source card; Enter toggles it.

Accessibility

  • The sidebar is an aside labelled "Chat history" with a nav of conversations; the current one has aria-current="page".
  • Streaming answers set aria-busy. A polite live region announces generation, completion time, stops, and errors.
  • The model switcher is a button with aria-haspopup="listbox" and a listbox using aria-activedescendant.
  • Citation chips are labelled with source number, title, and domain; the source card is a role="dialog" linked with aria-controls.
  • Thinking, tool detail, and source list toggles use aria-expanded and aria-controls. Icon buttons all have labels.

Motion

  • Streamed words fade and unblur in with a CSS keyframe; code lines fade in as they arrive.
  • Answer height follows content on a spring through a ResizeObserver, so streaming grows instead of jumping.
  • The model pill grows into its menu as one surface and shrinks back around the new name.
  • Switching answer versions slides in the direction of travel. A new conversation title scrambles in.
  • The wide sidebar springs its width open and shut; on narrow layouts it slides over the thread as a drawer.
  • Reduced motion stops the word and line keyframes and spinners, removes offsets and blur, and uses short fades.

Responsive behavior

  • Below 720px root width the sidebar becomes a drawer over the thread with a scrim, closed by Escape or a tap outside.
  • The main column is a size container. At 560px and below the thread, dock, and header padding tighten; at 380px the header notice hides.
  • Message hover actions are always visible on devices without hover.

Performance

  • Every stream event patches state, so each chunk re-renders the active answer. Batch tiny tokens into larger chunks in respond.
  • A ResizeObserver keeps the thread pinned to the bottom while you are within 56px of it; scrolling up releases it and shows a jump button.
  • Messages are not virtualized. Very long conversations should load older messages on demand.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Use for an assistant or copilot that streams answers, shows reasoning and tool use, and cites sources.
  • Write respond as an async generator that yields ChatStreamEvent objects and passes the signal to fetch. Write citations in the text as [1], [2], matching the sources event.
  • Conversations are uncontrolled after mount; persist them from onConversationsChange, ideally debounced since it fires per chunk.
  • Markdown supports headings, lists, quotes, tables, and fenced code with basic regex highlighting from markdown.tsx; swap in your own highlighter if you need more languages.
  • The reasoning panel renders with StreamText from markdown.tsx; reuse it for any plain streamed text next to the chat.
  • Attachments are images only, up to four, via picker, paste, or drop. They arrive as blob: URLs, so upload them inside respond if the model needs them.
/components/blocks/ai-chat/markdown

The full library index for assistants is at /llms.txt.

Related

AI composerProBlockA focused assistant thread where messages lift out of the composer and replies stream in.Chat threadComponentA chat thread with grouped messages, reactions, read receipts, typing, and a composer with attachments.Agent runProBlockA live AI agent run: steps stream in, tool calls expand, a diff waits for approval, and it all folds into a result.Support conversationProBlockA responsive message thread with useful quick replies and live feedback.Text shimmerComponentShow ongoing work with a calm light across the words.
PreviousPricing calculatorNextCheckout summary
Arc · 75 block pagesllms.txt

On this page

  • Preview
  • When to use
  • When not to use
  • Installation
  • Usage
  • API reference
  • Keyboard
  • Accessibility
  • Motion
  • Responsive behavior
  • Performance
  • Notes for AI
  • Related
View as Markdown

Today

Previous 7 days

Emma CollinsTeam plan
Atlas 4

Model

  • Atlas 4 DeepThinks longer for analysis and code
  • Atlas 4Balanced for everyday work
  • Atlas 4 SwiftFastest answers, no reasoning
Sample responses

What are we working on?

Enter to send, Shift Enter for a new line