One chat message with avatar, author, time, streaming Markdown, attachments, actions and response branches.
Example
import {
Message, MessageContent, MessageResponse, MessageActions, MessageAction,
} from "@elements/ui/message";
import { Icon } from "@elements/ui/icon";
<Message from="user" author="Ada" time={m.createdAt}>
<MessageContent>{m.text}</MessageContent>
</Message>
<Message from="assistant" author="Claude" showAvatar>
<MessageContent>
<MessageResponse markdown={reply.text} streaming={reply.streaming} />
</MessageContent>
<MessageActions>
<MessageAction label="Retry" tooltip="Regenerate" onclick={() => retry(reply)}><Icon name="refresh-cw" /></MessageAction>
<MessageAction label="Copy" onclick={() => copy(reply.text)}><Icon name="copy" /></MessageAction>
</MessageActions>
</Message>
Parts
| Part |
What it is |
Message |
An <article> for one message. Resolves data-variant (bubble, flat) and data-align (start, end) from the sender. |
MessageContent |
The body: a bubble for the user, flat text for the assistant. |
MessageResponse |
Safe streaming Markdown (CommonMark and GFM): highlighted code with copy and download, tables with copy and download menus, images with download, and a confirmation before any link opens. |
MessageActions |
A labelled group of actions. |
MessageAction |
A ghost icon button with an optional tooltip; toggle makes it a pressed/unpressed button. |
MessageToolbar |
A row with space between, for a branch selector and actions. |
MessageBranch |
Alternative versions of a response, one shown at a time. |
MessageBranchContent |
Each child element is one branch. |
MessageBranchSelector |
Previous, page and next. Hidden when there is only one branch. |
MessageBranchPrevious / MessageBranchNext |
Step through branches, wrapping at the ends. |
MessageBranchPage |
"2 of 3", announced politely. |
MessageLoading |
Three dots and a status label while a reply is pending. |
.message-code |
A code block inside MessageResponse: language, download and copy buttons, highlighted scrolling code. |
.md-table |
A table inside MessageResponse: a bar with Copy table (Markdown, CSV, TSV) and Download table (CSV, Markdown) menus. |
.md-image |
An image inside MessageResponse, with a Download image button on hover and focus. |
.message-link-dialog |
The link safety dialog: the full url, Copy link and Open link. |
Slots
| Slot |
Part |
Content |
default |
Message |
MessageContent, Attachments, MessageActions, MessageToolbar. |
avatar |
Message |
A custom avatar in place of the Avatar from avatar and author. |
default |
MessageContent |
Text or a MessageResponse. |
default |
MessageAction |
The icon. |
default |
MessageBranchContent |
The branches: each child element is one. |
default |
MessageBranchPrevious / Next |
A custom icon (chevrons by default). |
Keyboard
| Keys |
Action |
Tab |
Moves through actions, branch buttons, links and the code, table and image controls. Closes an open table menu. |
ArrowDown / ArrowUp |
In a table menu: the next or previous item, wrapping. |
Home / End |
In a table menu: the first or last item. |
Escape |
Closes a table menu (focus returns to its button) or the link dialog without opening the link. |
Enter |
Activates the focused button. |
Space |
Activates the focused button. |
Data attributes
| Attribute |
Values |
On |
Description |
data-from |
"user" | "assistant" | "system" |
.message |
|
data-variant |
"bubble" | "flat" |
.message |
Resolved from variant and from. |
data-align |
"start" | "end" |
.message |
Resolved from align and from. |
data-grouped |
present |
.message |
|
data-streaming |
present |
.message-response |
|
data-incomplete |
present |
.message-response a |
|
data-caret |
"block" | "circle" |
.message-response |
|
data-animation |
"fade" | "blur" | "slide-up" |
.message-response |
Set when animated is on. |
data-state |
"on" | "off" |
.message-action (toggle), .message-code-swap (copied) |
|
data-branch |
the shown index |
.message-branch |
|
data-branches |
the branch count |
.message-branch |
|
Accessibility
- Each message is an
<article> named by its author, or by its role (You, Assistant, System).
- The time is a
<time datetime> element.
- MessageActions is a labelled group; each action is named by label or tooltip, and toggles set aria-pressed.
- MessageResponse sets aria-busy while streaming, so screen readers wait for the finished text.
- The code copy button is named Copy code, then Copied; the two icons share one cell, so it never changes size.
- The branch page (2 of 3) is a polite live region; previous and next are disabled when there is one branch.
- MessageLoading is role=status with a label.
- Table menu buttons have aria-haspopup=menu and aria-expanded; the menu is role=menu with menuitems and arrow keys.
- While streaming, every copy and download control is disabled, so nobody copies an unfinished reply.
- Link safety uses the Dialog: focus moves in, Escape closes, focus returns to the link.
- While a reply streams in, only the block being written re-renders, so a reader's selection in an earlier paragraph survives each token.
- Under dir=rtl the branch chevrons mirror, so Previous points back toward the start.
See also