Chat
A ready-made conversation UI combining `ChatMessages` and `ChatInput` — pass a `messages` array in and handle `send`, no wiring between the two required.
<UiChat />Messages
messages drives the whole conversation, oldest first. Chat is ChatMessages and ChatInput together, and the composer's draft and attachments are internal to it — so the only thing you handle is the send event, by pushing onto this array.
No wiring between the two components required
Using ChatMessages and ChatInput separately (see their own doc pages) means owning the draft ref, the attachments ref, and pushing onto the messages array yourself. Chat does all of that internally — you only ever see finished messages, via `send`.
Group window
groupWindow is how many minutes apart two consecutive messages from the same sender can be and still read as one run — five by default. Widen it for a slow, considered conversation; narrow it where a gap of a minute genuinely means a new thought. It's forwarded straight through to ChatMessages.
Auto scroll
autoScroll follows the newest message as messages grows — but only when the reader was already near the bottom, so it never yanks them away from something they scrolled up to read. Turn it off for a transcript people are meant to browse rather than follow live.
Empty text
emptyText stands in for the list before there's anything in it. Say what would fill it — “No messages yet. Say hello.” — rather than only reporting the emptiness, since the composer right below is the answer.
No messages yet. Say hello.
Placeholder
placeholder is the hint in the empty composer, forwarded to the inner ChatInput. Naming the room or the person — “Message #design” — doubles as a reminder of where the message is about to go.
Disabled
disabled locks the composer outright: no typing, no attachments, no sending.
Loading
loading locks the composer's send button and swaps its icon for a spinner — for the window while a send request is in flight.
Variant
variant is forwarded to the composer, styling its ring and background the same way it would on a bare ChatInput.
Color
color themes the composer's send button, and doubles as the fallback bubble color for own messages that don't set a color of their own.
Status
status is the fallback delivery state for own messages that don't carry their own. It's rarely useful as a blanket default — real delivery differs message to message — so reach for it only when every message in the list genuinely shares one, and set status per message otherwise.
Allow reactions
allowReactions is the fallback for messages that don't set their own, so setting it false turns reactions off across the whole conversation without touching a single message object. Worth doing wherever there's nowhere to store a reaction.
Allow attachments
allowAttachments shows the composer's paperclip, forwarded to the inner ChatInput. Turn it off wherever files have nowhere to go, rather than accepting them and dropping them silently.
Allow emojis
allowEmojis shows the composer's emoji button, which inserts into the draft at the cursor. Turning this and allowAttachments both off leaves a plain text composer.
Multiple
multiple decides whether the composer's file picker takes more than one file at a time. Set it false where a message can only carry one thing, so the constraint lands in the dialog rather than in an error afterwards.
Accept
accept is the comma-separated list of file types the composer's picker offers — MIME types like image/* or extensions like .pdf. It filters the dialog rather than validating the result, so still check what actually arrives.
Max rows
maxRows is how tall the composer's textarea grows before it starts scrolling, six rows by default. Lower it in a narrow panel, where a long draft would otherwise push the conversation off the screen entirely.
API Reference
Generated from the component's source — props, slots and emits as the component actually declares them.
Props
ChatMessageItem[][]number5booleantruebooleanfalse"neutral" | "primary" | "secondary" | "success" | "error" | "warning" | "info" | "pending"'primary'"sending" | "sent" | "delivered" | "read" | "failed"booleantruebooleantruestringSlots
actionsEmits
toggle-reaction[message: ChatMessageItem, emoji: string]send[payload: { content: string; attachments: File[] }]remove-attachment[file: File, index: number]Types
type Variant = "outline" | "soft";type Color = "neutral" | "primary" | "secondary" | "success" | "error" | "warning" | "info" | "pending";type MessageStatus = "sending" | "sent" | "delivered" | "read" | "failed";interface ChatMessageItem {
/**
* Unique identifier, used as the list key when rendered via `ChatMessages`. Falls back to the array index if omitted.
*/
id?: string | number;
/**
* The plain-text message content. Ignored if the default slot is used instead.
*/
content?: string;
/**
* Whether this message was sent by the current viewer — aligns it to the right and hides its avatar/name.
* @defaultValue false
*/
own?: boolean;
/**
* The sender's display name, shown above the bubble for non-own messages (unless `grouped`).
*/
name?: string;
/**
* The sender's avatar image URL. Falls back to initials, same as `Avatar`.
*/
avatarSrc?: string;
/**
* The sender's first name, used for the avatar's fallback initials.
*/
firstName?: string;
/**
* The sender's last name, used for the avatar's fallback initials.
*/
lastName?: string;
/**
* When to show this message: a `Date` is formatted as a local time (e.g. '10:32 AM'); a string is displayed as-is.
*/
timestamp?: string | Date;
/**
* Delivery status, shown as a small icon next to the timestamp. Only rendered for `own` messages.
*/
status?: ChatMessageStatus;
/**
* The bubble color for `own` messages. Has no effect on received messages, which are always neutral.
* @defaultValue 'primary'
*/
color?: ChatMessageColor;
/**
* Emoji reactions to show as pills below the bubble. Clicking one toggles it — the count and
* `reacted` state are your responsibility to update in response to the `toggle-reaction` event.
*/
reactions?: ChatMessageReaction[];
/**
* Shows a trigger (revealed on hover) that opens an emoji picker for reacting to the message.
* @defaultValue true
*/
allowReactions?: boolean;
}