Chat

Primitives for building a chat interface — a message list, message bubbles, and a composer.

What is dotUI?
A design-system builder: compose colors, typography and per-component styles, preview them live, then export the code you own.
const initialMessages = /* ... */;

<div className="flex h-80 w-full max-w-md flex-col gap-3">
  <Conversation className="rounded-(--radius-panel) border border-border-muted">
    {messages.map((message) => (
      <Message key={message.id} role={message.role}>
        <MessageContent>{message.text}</MessageContent>
      </Message>
    ))}
  </Conversation>
  <PromptInput
    onSubmit={(e) => {
      e.preventDefault()
      if (!draft.trim()) return
      setMessages((current) => [
        ...current,
        { id: current.length + 1, role: "user" as const, text: draft },
      ])
      setDraft("")
    }}
  >
    <PromptInputTextarea
      value={draft}
      onChange={(e) => setDraft(e.target.value)}
      placeholder="Ask anything…"
      aria-label="Message"
    />
    <PromptInputToolbar>
      <PromptInputSubmit isIconOnly aria-label="Send message">
        <ArrowUpIcon />
      </PromptInputSubmit>
    </PromptInputToolbar>
  </PromptInput>
</div>

Installation

npx shadcn@latest add @dotui/chat

Usage

import { Conversation, Message, MessageContent } from "@/ui/chat"
<Conversation>
  <Message role="user">
    <MessageContent>How do I center a div?</MessageContent>
  </Message>
  <Message role="assistant">
    <MessageContent>Center it with place-items.</MessageContent>
  </Message>
</Conversation>

Anatomy

Conversation is the scroll container for the message list. Each Message sets the role its children style against: user renders MessageContent as a contained bubble aligned to the end of the row, assistant renders it plain and full-width. MessageAvatar is optional and sits on the sender's side of the row.

import { Conversation, Message, MessageAvatar, MessageContent } from "@/ui/chat"
<Conversation>
  <Message role="assistant">
    <MessageAvatar name="AI" />
    <MessageContent>{/* message body */}</MessageContent>
  </Message>
</Conversation>

PromptInput is the composer. It renders a form, so PromptInputSubmit — or pressing Enter in the textarea — submits it; Shift+Enter inserts a newline. The textarea grows with its content, and the shell is the same input group the rest of your fields use, so it follows their style, radius and density.

import {
  PromptInput,
  PromptInputSubmit,
  PromptInputTextarea,
  PromptInputToolbar,
} from "@/ui/chat"
<PromptInput onSubmit={handleSubmit}>
  <PromptInputTextarea placeholder="Ask anything…" aria-label="Message" />
  <PromptInputToolbar>
    {/* attachments, tools… */}
    <PromptInputSubmit isIconOnly aria-label="Send message">
      <ArrowUpIcon />
    </PromptInputSubmit>
  </PromptInputToolbar>
</PromptInput>

Examples

Basic

How do I center a div?
Give the parent a grid display and center its place-items. Two lines, no margins to guess at.
And if the parent is already a flex row?
Then centering justify-content and align-items does the same job along the two axes.

With Avatars

ME
Can you summarize the release notes?
AI
Three things shipped: a faster registry build, per-component radius roles, and dark-mode fixes for charts.

Prompt Input

With Toolbar

API Reference

Conversation

A scrollable list of chat messages.

Supports all div attributes.

PropType

Message

A single turn in a conversation. Lays out the avatar and the content, and exposes the role its children style against.

Supports all div attributes.

PropType

MessageContent

The body of a message — text, or any rich content the message carries.

Supports all div attributes.

PropType

MessageAvatar

The avatar of the message sender.

Supports all span attributes.

PropType
"lg" | "md" | "sm"
string

PromptInput

The composer users type their message into. Renders a form, so a submit button — or pressing Enter in the textarea — submits it.

Supports all form attributes.

PropType

PromptInputTextarea

The auto-growing textarea of the composer. Enter submits the surrounding form, Shift+Enter inserts a newline.

Supports all textarea attributes.

PropType

PromptInputToolbar

The row of actions below the textarea, such as attachments or the submit button.

Supports all div attributes.

PropType

PromptInputSubmit

The button that submits the composer.

Supports all button attributes.

PropType
union
union

Last updated on 8/28/2026