Message
A single conversational turn in a message log.
View code
<div mix={[vstack({ gap: 6, align: "stretch" })]}>
<Message>
<Message.Avatar>
<Avatar>
<Avatar.Fallback>AR</Avatar.Fallback>
</Avatar>
</Message.Avatar>
<Message.Header>
<strong>Ana Ruiz</strong>
<time dateTime="2026-09-21T14:02">14:02</time>
</Message.Header>
<Message.Content>
<Bubble variant="muted">
<Bubble.Content id="turn-1-text">
The deploy finished but the worker is still serving the old bundle. Is there a cache
I should be busting?
</Bubble.Content>
</Bubble>
</Message.Content>
<Message.Footer>
<Button
type="button"
variant="ghost"
size="sm"
aria-label="Copy message"
commandfor="turn-1-text"
command={COPY_COMMAND}
mix={[copyToClipboard()]}
>
<CopyIcon />
</Button>
<Button type="button" variant="ghost" size="sm" aria-label="Reply to Ana Ruiz">
<ReplyIcon />
</Button>
</Message.Footer>
</Message>
<Message>
<Message.Avatar>
<Avatar>
<Avatar.Fallback>SX</Avatar.Fallback>
</Avatar>
</Message.Avatar>
<Message.Header>
<strong>Sergio</strong>
<time dateTime="2026-09-21T14:05">14:05</time>
</Message.Header>
<Message.Content>
<Bubble align="end">
<Bubble.Content>
The bundle is fingerprinted, so that is the CDN holding a stale index.
</Bubble.Content>
</Bubble>
</Message.Content>
</Message>
<Message.Group>
<Message>
{/* A run's later turns carry the avatar, so the turns above it reserve its column. */}
<Message.Avatar aria-hidden="true">
<span mix={[is("2.5rem")]} />
</Message.Avatar>
<Message.Header>
<strong>Ana Ruiz</strong>
<time dateTime="2026-09-21T14:07">14:07</time>
</Message.Header>
<Message.Content>
<Bubble variant="muted">
<Bubble.Content>Purging it now.</Bubble.Content>
</Bubble>
</Message.Content>
</Message>
<Message>
<Message.Avatar>
<Avatar>
<Avatar.Fallback>AR</Avatar.Fallback>
</Avatar>
</Message.Avatar>
<Message.Content>
<Bubble variant="muted">
<Bubble.Content>That did it — thank you.</Bubble.Content>
</Bubble>
</Message.Content>
</Message>
</Message.Group>
</div>Installation
An ordinary dependency: install it, import the theme once, and import the component where it is used.
npm add @sdxc/uiimport "@sdxc/ui/theme.css";Usage
import { Message } from "@sdxc/ui";Renders the message row as a two-column grid whose "avatar" area spans only the
header and content rows, anchoring Message.Avatar to the bottom edge
of Message.Content, regardless of whether Message.Footer renders.
Composition
The parts the component publishes, each a static property of the host.
MessageMessage.AvatarRenders Message.AvatarProps.children as the row's avatar slot, aligned to the"avatar"area's block-end edge so it tracks the bottom edge of Message.Content.Message.HeaderRenders Message.HeaderProps.children as the row's identity line, wrapping until theui-messagecontainer passes26rem, then settling onto one row with the sender's name first and later children as secondary metadata.Message.ContentRenders Message.ContentProps.children as the row's content slot, capped to a comfortable reading measure and never narrower than its grid area.Message.FooterRenders Message.FooterProps.children as the row's action slot, occupying the grid's"footer"area beneath Message.Content and never reached by Message.Avatar's bottom anchor.Message.GroupRenders Message.GroupProps.children as a run of consecutive Message rows sharing the same sender, stacked with a hairline gap that reads as one continuous turn.
Props
Read from the component's own types, so every prop, every default and every allowed value is listed.
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The row's compound parts: Message.Avatar, Message.Header, Message.Content, and an optional Message.Footer. |
Also accepts everything in TagProps<"article">.
Message.Avatar
| Prop | Type | Description |
|---|---|---|
children | RemixNode | An Avatar instance identifying the message's sender. |
Also accepts everything in TagProps<"div">.
Message.Header
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The sender's name, typically followed by a timestamp. |
Also accepts everything in TagProps<"header">.
Message.Content
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The message's own surface — a Bubble, an attachment card, or any other rendered turn content. |
Also accepts everything in TagProps<"div">.
Message.Footer
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The row's actions, typically a copy Button and a like Button. |
Also accepts everything in TagProps<"footer">.
Message.Group
| Prop | Type | Description |
|---|---|---|
children | RemixNode | A run of consecutive Message rows sharing the same sender. |
Also accepts everything in TagProps<"div">.