<Chat.MessageList>
<Chat.DateSeparator>Hier</Chat.DateSeparator>
<Chat.MessageGroup align="start">
<Chat.MessageSender avatar={<Avatar.Root …/>} name="Camille Dubois" />
<Chat.Message variant="other">
Bonjour, je serai sur place 30 minutes avant le match.
<Chat.MessageTime dateTime="2026-06-11T18:42">18:42</Chat.MessageTime>
</Chat.Message>
</Chat.MessageGroup>
</Chat.MessageList>
<Chat.Composer value={draft} onValueChange={setDraft} onSubmit={send} sendLabel="Envoyer" />The list keeps itself pinned to the newest message while the user is at the bottom, and stops following as soon as they scroll up — so an arriving message never yanks the view away from what they are reading.
Group consecutive messages from one author into a single Chat.MessageGroup;
the sender block is rendered once per group, not once per message.
Chat.ConversationItem is the list-of-threads row, with unreadCount capped at
"99+".
API
Chat.Composer
| Prop | Type | Default | |
|---|---|---|---|
onSubmit | () => void | required | Fired on send button click, on (Cmd|Ctrl)+Enter, and — when
submitOnEnter is set — on plain Enter. |
onValueChange | (value: string) => void | required | |
sendLabel | string | required | |
value | string | required | |
disabled | boolean | false | Composer unusable (e.g. archived conversation). |
error | ReactNode | — | |
hint | ReactNode | — | |
maxLength | number | — | Soft character limit: shows a live counter and disables send once exceeded. The textarea itself is not capped so the writer can trim an over-long draft instead of having input silently dropped. |
placeholder | string | — | |
sending | boolean | false | A post is in flight: button shows a spinner, submit is suppressed. The textarea stays enabled so the writer keeps focus and can draft the next message. |
submitOnEnter | boolean | false | Send on a plain Enter (Shift+Enter still inserts a newline), matching the mobile/messenger convention. Cmd/Ctrl+Enter always sends regardless. |
Plus every <form> prop. Source: chat/components/chat-composer.tsx.
Chat.ConversationItem
| Prop | Type | Default | |
|---|---|---|---|
title | string | (string & Iterable<ReactNode>) | (string & Promise<AwaitedReactNode>) | (string & ReactElement<unknown, string | JSXElementConstructor<any>>) | (string & ReactPortal) | undefined | required | |
badges | ReactNode | — | Subject/status badges, rendered after the title. |
description | ReactNode | — | Secondary line: last-message preview or "no messages yet" copy. |
leading | ReactNode | — | Leading visual (typically an avatar), rendered before the text column. |
timestamp | ReactNode | — | |
unreadCount | number | 0 | Messages the reader has not seen; > 0 bolds the row and shows a count. |
unreadLabel | string | — | Accessible label for the unread badge (the visible glyph is a bare count, capped at "99+"). Spell out the true total here, e.g. "3 unread messages", so screen readers don't announce a contextless number. |
render | ComponentRenderFn<HTMLProps, {}> | ReactElement<unknown, string | JSXElementConstructor<any>> | — | Allows you to replace the component's HTML element
with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
Plus every <div> prop. Source: chat/components/chat-conversation-item.tsx.
Chat.DateSeparator
Plus every <div> prop. Source: chat/components/chat-date-separator.tsx.
Chat.ExternalLinkDialog
| Prop | Type | Default | |
|---|---|---|---|
cancelLabel | ReactNode | required | |
confirmLabel | ReactNode | required | |
onClose | () => void | required | |
title | ReactNode | required | |
url | string | null | required | The pending external URL; null keeps the dialog closed. |
description | ReactNode | — | Warning copy shown above the URL, e.g. "Do you trust this link?". |
Plus the DOM props of the element it renders. Source: chat/components/chat-external-link-dialog.tsx.
Chat.Message
| Prop | Type | Default | |
|---|---|---|---|
variant | "other" | "own" | required | Which side of the conversation the bubble belongs to. own is the
signed-in user. This only tints and notches the bubble — the enclosing
ChatMessageGroup is what aligns it left or right. |
render | ComponentRenderFn<HTMLProps, {}> | ReactElement<unknown, string | JSXElementConstructor<any>> | — | Allows you to replace the component's HTML element
with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
Plus every <div> prop. Source: chat/components/chat-message.tsx.
Chat.MessageGroup
| Prop | Type | Default | |
|---|---|---|---|
align | "end" | "start" | required | |
render | ComponentRenderFn<HTMLProps, {}> | ReactElement<unknown, string | JSXElementConstructor<any>> | — | Allows you to replace the component's HTML element
with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
Plus every <div> prop. Source: chat/components/chat-message-group.tsx.
Chat.MessageList
| Prop | Type | Default | |
|---|---|---|---|
followThreshold | number | FOLLOW_THRESHOLD | How close to the bottom (px) still counts as "following". |
header | ReactNode | — | Pinned above the messages inside the scroll area (e.g. "load older"). |
jumpToLatestLabel | ReactNode | — | Label for the floating "jump to latest ↓" button shown while the reader is away from the bottom and new content may arrive. Omit to disable the affordance. |
onFollowChange | ((following: boolean) => void) | — | Fired when the reader starts or stops following the bottom of the thread. Lets consumers react to the internal follow state (analytics, unread markers, …) beyond the built-in jump-to-latest affordance. |
Plus every <div> prop. Source: chat/components/chat-message-list.tsx.
Chat.MessageSender
| Prop | Type | Default | |
|---|---|---|---|
name | ReactNode | required | |
avatar | ReactNode | — | |
badge | ReactNode | — |
Plus every <div> prop. Source: chat/components/chat-message-sender.tsx.
Chat.MessageText
| Prop | Type | Default | |
|---|---|---|---|
children | string | required | |
onLinkClick | ((url: string) => void) | — |
Plus every <span> prop. Source: chat/components/chat-message-text.tsx.
Chat.MessageTime
Plus every <time> prop. Source: chat/components/chat-message-time.tsx.
Chat.UnreadSeparator
Plus every <div> prop. Source: chat/components/chat-unread-separator.tsx.