Chat
Organism
A controlled assistant conversation with independently scrolling messages, clear author and provider identities, and an anchored multiline composer. The parent supplies the bounds; Chat fills the available height without choosing a fixed height of its own.
Playground
Every control sets a real prop of ChatProps. The JSX below updates as you go.
Web
iOS
Android
JSX · ChatProps
Variants
10 examples from src/organisms/chat/chat.md, each rendered live from its own JSX.
Anatomy
1
Thread
2
Assistant message
3
User message
4
Avatar
5
Composer
Dimmed parts appear only in some states or variants.
Props
28 props on ChatProps, grouped as they are declared in source. Required props are marked *.
Accessibility and keyboard
Keyboard
Type
Edits the value
Tab
Next field
Escape
Clears when clearable
Semantics
Roles
header
heading
progressbar
text
States
busy
ARIA on web
aria-busy
aria-hidden
aria-label
aria-level
aria-live
From the docs
Messages remain application-owned ChatMessageData: keep each id stable while updating content during streaming. pending shows a three-dot thinking indicator until an explicitly streaming message arrives; pass pendingIcon to identify its provider. Streaming replies retain their own Responding indicator. Both animations stop when their state ends and stay still under Reduce Motion. providerIcon accepts an application-supplied provider logo beside the author; label the image or icon with the provider nam
ChatThread follows new content while the reader is within 48 points of the bottom. Scrolling up to read older messages pauses following; returning to the bottom resumes it. Message updates, streaming text, question-height changes, and viewport resizing coalesce into a tail adjustment after layout settles. Scrolling is immediate and never animated, so it does not add motion when text streams or Reduce Motion is enabled. The overflowing thread is keyboard focusable with a visible focus frame. The native app or owni
Set onAttach to show the accessible paperclip action. The app owns file picking and uploading, passes composer attachments, and removes a staged file through onRemoveAttachment(id). A ChatAttachmentData has an id, name, optional uploading or error flags, and optional notice text. Uploading and failed files block sending; remove a failed file or replace it after retrying. attaching also blocks attaching and sending while the app opens a picker or uploads. Saved message attachments use the same me
Both answer callbacks and an enabled form are required for interaction. disabled, pending, and active streaming lock the current question. Use questionsDisabled for an inactive earlier batch: it shows every original question and option read-only, without navigation actions. questionsSubmitted shows saved answers with an Answers sent receipt. Multiple-choice receipts include every selected label and custom text; an answer-mode override is identified as Multiple answers selected by you. Question labels and de
The current question is framed by the existing compact, flat selected Card: a soft theme tint and primary border distinguish its counter, answers and actions from the surrounding conversation. Saved receipts and inactive question history remain unframed. The Card is visual only, so answer controls retain their own accessible roles and focus behavior.
Markdown reuses Chat's safe grammar and renderer for standalone documents. It preserves heading levels one through six, emphasis, inline and fenced code, quotes, ordered and unordered lists, nested indentation, static checked/unchecked task lists, horizontal rules, and pipe tables. Tables use Canvas DataTable's container-responsive stacked layout on narrow surfaces, retaining every column on iOS too. Checklists are read-only Canvas selection controls; reading a document never changes its source. HTML, links and i
Platform skins
The playground's props on each platform: same tree, native shapes, type and touch sizes.
Usage
Messages remain application-owned ChatMessageData: keep each id stable while updating content during streaming. pending shows a three-dot thinking indicator until an explicitly streaming message arrives; pass pendingIcon to identify its provider. Streaming replies retain their own Responding indicator. Both animations stop when their state ends and stay still under Reduce Motion. providerIcon accepts an application-supplied provider logo beside the author; label the image or icon with the provider name for assistive technology. provider remains an optional supplementary text label such as the transport name. error adds a visible failure label; notice preserves delivery or fallback information. footer anchors connection, review, or other actions below the composer and outside the scrollport.
Pass actions on any message for app-owned choices beneath its content: each has a stable id, a literal label, and optional primary. Chat, ChatThread, and ChatMessage call onAction(messageId, actionId) when chosen. Choices wrap at narrow widths and use each platform’s Button. disabled, pending, any streaming message in the thread, or an absent callback prevents activation. The app owns saving the choice, setting busy state while it is accepted, duplicate prevention, and removing resolved or historical actions. Actions do not send a composer draft or submit question answers.
Assistant content supports paragraphs, headings, lists, quotes, fenced code, bold, emphasis, and inline code through React Native text. HTML, images, and links stay literal text and never load or execute remote content. plain renders all source punctuation literally; user messages are always plain text. This is a small safe markdown subset rather than a complete CommonMark renderer.
Tokens
Read from the playground render. Values follow the scheme and the ion hue.
--bg2
--fd
--ft
--ion
--ion-fg
--ion-soft
--ion-tx
--ln
--ln2
--sf
--sf2
--tx3