MessageBubble
<caos-message-bubble>
one message, with its author, its time and its body
May be placed on a record page, an app’s home page and a page inside an app.
Inputs
Section titled “Inputs”| Name | Attribute | Description | Type | Default | Required |
|---|---|---|---|---|---|
author |
author, markup only |
Who said it. Also the source of the initials in the avatar when no avatar text is given — the first letter of each of the first two words. | text | none declared | Optional |
at |
at, markup only |
When it was said, as an ISO-8601 instant. Drawn as a time of day in the reader’s own locale, because the day is said by the divider above rather than on every message. A value the runtime cannot read as a date draws no time rather than drawing a wrong one. | text | none declared | Optional |
body |
body, markup only |
What they said, as markdown. Settable as a property too, and the property wins — a message carries newlines and can run long, and an attribute holding one goes through the browser’s own attribute rules before this component sees it. | text | none declared | Optional |
avatar |
avatar, markup only |
What the avatar shows, when the initials taken from the author are not what you want. One or two characters; it is decorative and is hidden from screen readers, because the author’s name is already read out beside it. | text | none declared | Optional |
grouped |
grouped, markup only |
This message continues the one above it: the avatar, name and time are not drawn, and only the body appears. Decided by whatever draws the list — see the notes above. | boolean | false | Optional |
highlighted |
highlighted, markup only |
Mark this as the message that was navigated to — from a search result, or a link into the conversation. Held by the attribute rather than by an animation that ends, so a reader who looked away can still see which one it was. | boolean | false | Optional |
Events
Section titled “Events”This piece raises no events.
| Name | What goes in it |
|---|---|
footer |
Anything offered ABOUT this message — a reaction, a reply count, an action a surface knows how to run. Deliberately a slot and not a set of inputs: what can be done about a message is the application’s vocabulary, not the library’s, and a component that shipped its own action schema would be shipping one application’s. |
Styling hooks
Section titled “Styling hooks”| Design token | What it controls |
|---|---|
--caos-color-text |
The message body and the author’s name. |
--caos-color-text-subtle |
The time beside the name. |
--caos-color-text-muted |
The initials in the avatar. |
--caos-color-surface-2 |
The avatar behind the initials, the tint on a highlighted message, and behind a mention. |
--caos-color-border |
The avatar’s edge, and the rules in a table or a code block. |
--caos-color-accent |
A link in the body, a mention, and the control that opens a folded message. |
--caos-font |
The typeface the message is set in. |
--caos-font-mono |
Code, inline and in a block. |
--caos-text-body |
The size of the message body. |
--caos-text-label |
The time, the initials and the fold control. |
--caos-font-weight-label |
The weight of the author’s name, and of a mention in the body. |
--caos-space-1 |
The space above and below one message. |
--caos-space-2 |
The gap between the avatar and the message. |
--caos-space-3 |
The inset from the edge of the conversation. |
--caos-space-4 |
The indent of a list in the body. |
--caos-radius-pill |
The roundness of the avatar. |
--caos-radius-sm |
The roundness of a code block, an inline code pill and a mention. |
--caos-focus-ring |
The ring on the fold control and on a link in the body. |
Methods
Section titled “Methods”Nothing else drives this piece by calling it.
Readable state
Section titled “Readable state”Nothing on this piece can be read back.
Styling parts
Section titled “Styling parts”| Part | Which piece of it | When it is there |
|---|---|---|
::part(message) |
the whole row | Always |
::part(avatar) |
the initials disc | Always |
::part(header) |
the name and time line | Always |
::part(author) |
the name | Always |
::part(time) |
the time | Always |
::part(body) |
the rendered message | Always |
::part(footer) |
whatever was slotted under the message | Always |
When to use it
Section titled “When to use it”One thing somebody said, in a conversation with other things somebody said. A single message standing alone with nothing before or after it is a piece of text, and wants whatever the surrounding page uses for text.
What to use instead
Section titled “What to use instead”- KeyValueRow — The subject is a field and its value rather than a person and what they said.
- NoticeBanner — The platform is telling the reader something, rather than a person telling another person. A message has an author; a notice does not.
- DetailSection — The content is a record’s own long text. It is one field of one record, not an entry in a conversation, and nothing about it is grouped or timed.
Accessibility
Section titled “Accessibility”Each message is a role="article", so a screen reader can move message by message instead of paragraph by paragraph through a whole conversation. The time is a <time> with a machine-readable datetime, so “9:14 AM” is not the only form of it available. The avatar is aria-hidden: it repeats the author’s name, and reading both says the same person twice before every message. The fold control carries aria-expanded. Left to the author: the AUTHOR name. A grouped message draws no name by design, so a reader moving article by article through a run of grouped messages hears the bodies without the name — which is correct, because the name did not change, and is the reason grouping must only be set when it genuinely did not.
Examples
Section titled “Examples”A message with its header
Section titled “A message with its header”The first message from somebody: avatar, name, time, body.
{ "id": "example", "section": "A message with its header", "columns": 1, "items": [ { "id": "message_bubble_1", "type": "component", "key": "message_bubble", "inputs": { "author": "Ada Lovelace", "at": "2026-09-13T09:14:00.000Z", "body": "Pushed the fix — it was **the index**, not the query." } } ]}<caos-message-bubble author="Ada Lovelace" at="2026-09-13T09:14:00.000Z" body="Pushed the fix — it was **the index**, not the query."></caos-message-bubble>The next message from the same person
Section titled “The next message from the same person”Grouped: no avatar, no name, no time. The message above said all three a moment ago, and repeating them is what makes a conversation read as a log file.
{ "id": "example", "section": "The next message from the same person", "columns": 1, "items": [ { "id": "message_bubble_1", "type": "component", "key": "message_bubble", "inputs": { "author": "Ada Lovelace", "at": "2026-09-13T09:14:00.000Z", "body": "Pushed the fix — it was **the index**, not the query." } }, { "id": "message_bubble_2", "type": "component", "key": "message_bubble", "inputs": { "author": "Ada Lovelace", "at": "2026-09-13T09:15:00.000Z", "body": "Plan reads back clean now.", "grouped": true } } ]}<caos-message-bubble author="Ada Lovelace" at="2026-09-13T09:14:00.000Z" body="Pushed the fix — it was **the index**, not the query."></caos-message-bubble><caos-message-bubble author="Ada Lovelace" at="2026-09-13T09:15:00.000Z" body="Plan reads back clean now." grouped></caos-message-bubble>A body with marks in it
Section titled “A body with marks in it”The small markdown a message may carry, drawn as nodes rather than as HTML.
{ "id": "example", "section": "A body with marks in it", "columns": 1, "items": [ { "id": "message_bubble_1", "type": "component", "key": "message_bubble", "inputs": { "author": "Grace Hopper", "at": "2026-09-13T10:02:00.000Z", "body": "Three things to check:\n\n- the `at` bound is inclusive\n- the filter reaches the index\n- an empty page says *why*\n\nSee https://example.test/notes for the rest." } } ]}<caos-message-bubble author="Grace Hopper" at="2026-09-13T10:02:00.000Z" body="Three things to check:
- the `at` bound is inclusive- the filter reaches the index- an empty page says *why*
See https://example.test/notes for the rest."></caos-message-bubble>