AI Conversation
Compose a reader-aware conversation viewport with messages and explicit copy feedback.
Compose your conversationLink to section
AIConversation displays a scrollable, labelled message list. It follows new content
while the reader is at the end and preserves their position when they scroll back.
Your application supplies messages and transport; this component makes no model requests.
Package availability
AIConversation, AIMessage and AIMessageActions are introduced by the
conversation primitives minor Changeset. Use the repository workspace until
that release is published. They are not exported by @pycolors/ui@1.6.1 or
earlier.
Follow the reader
Return explicitly
Keep application ownership
PreviewLink to section
You
How can I make the next step clearer for the person using this interface?Assistant
Start with one clear outcome and keep recovery visible. This is a fixed sample response.You
How can I make the next step clearer for the person using this interface?Assistant
Start with one clear outcome and keep recovery visible. This is a fixed sample response.You
How can I make the next step clearer for the person using this interface?Assistant
Start with one clear outcome and keep recovery visible. This is a fixed sample response.
Scroll up, then add a message: your reading position stays put. Choose Jump to latest to resume following. No model is connected.
The example runs here in the documentation. The Explorer link appears when this story is available in the published catalog; otherwise use this inline preview.
Controlled compositionLink to section
"use client";
import { AIConversation, AIMessage, AIMessageActions } from "@pycolors/ui";
type Message = { id: string; author: string; text: string };
export function Conversation({ messages }: { messages: Message[] }) {
return (
<AIConversation
label="Support conversation"
messagesLabel="Support messages"
>
{messages.map((message) => (
<AIMessage
key={message.id}
author={message.author}
actions={
<AIMessageActions
value={message.text}
copyAriaLabel={`Copy ${message.author} message`}
onCopy={(text) => navigator.clipboard.writeText(text)}
/>
}
>
{message.text}
</AIMessage>
))}
</AIConversation>
);
}Place AIComposer after the conversation. Keep request errors, retry and cancellation in your consumer, or use the AI Chat Block for the complete composed surface. This component does not parse Markdown or HTML.
Behavior and accessibilityLink to section
Supply semantic messagesLink to section
Children belong to an ordered list. Render AIMessage or native li elements,
with stable keys. The empty state belongs outside that list. Use a meaningful
label and messagesLabel when more than one conversation appears on the page.
Respect reading positionLink to section
The focusable viewport follows content and resize changes while at the end. Scrolling more than 32 pixels away pauses following. Returning near the end or choosing Jump to latest resumes it. Layout changes do not force a reader back to the bottom. Without ResizeObserver, React child updates still follow.
Announce request state in your applicationLink to section
The message list is not a live region: streaming tokens must not repeatedly interrupt a screen reader. Provide concise request-status announcements outside the list. Jumping uses immediate scrolling and restores viewport focus without animated motion. Keyboard and screen-reader verification remain part of your application's integration checks.
APILink to section
| Prop | Default | Purpose |
|---|---|---|
children | — | Semantic list items, usually AIMessage instances |
label | Conversation | Accessible viewport name |
messagesLabel | Messages | Accessible ordered-list name |
jumpLabel | Jump to latest | Visible return button label |
viewportClassName | — | Override the default max-h-[28rem] viewport styling |
className, native div props | — | Outer wrapper attributes and styling |
ref | — | Outer HTMLDivElement, not the inner viewport |
Slots: ai-conversation and ai-conversation-viewport. Caller classes use the
standard PyColors cn() precedence. The viewport owns its scroll handling and
focus behavior. Use a stable component key to reset an entire conversation.