Message
One chat message with sender, time, a bubble, reply quote, preview, attachment, reactions and delivery status.
Last updated
Show codeHide code
<ol aria-label="Conversation" class="flex flex-col gap-4">
<Message name="Ana Lima" time="9:41" datetime="2026-10-15T09:41">
<Avatar slot="avatar" name="Ana Lima" size="small" status="online" />
Can you check the launch brief before lunch?
</Message>
<Message me time="9:43" datetime="2026-10-15T09:43" status="read">
<span slot="reply">Can you check the launch brief before lunch?</span>
On it. The copy section needs one more pass.
</Message>
</ol>Add
npx @ava-ui/apogee add message
Uses @lucide/astro for the status glyphs. Pair with Avatar in the
avatar slot.
Usage
---
import Message from '@/components/apogee/Message/Message.astro'
---
<ol aria-label="Conversation">
<Message name="Ana" time="9:41">Hi!</Message>
<Message me time="9:42" status="sent">Hello.</Message>
</ol>
Anatomy
- Row — an
<li>(ordivwithas="div"); your own messages (me) run end to start. avatarslot — beside the bubble, aligned to its bottom.- Header —
<cite>for the sender and<time>for the time. - Bubble — the text; the corner nearest the sender is square. Holds the
replyquote above the text, and thepreviewandattachmentbelow it. reactionsslot — a row under the bubble.- Status — a glyph with screen-reader text; failures also show the text.
API
@composable — any other attribute passes through to the row.
| Prop | Type | Default | Description |
|---|---|---|---|
name |
string |
— | Sender, in <cite>. |
time |
string |
— | Shown time. |
datetime |
string |
— | Machine-readable time for <time datetime>. |
me |
boolean |
false |
Your own message: end-aligned, primary bubble. |
status |
'sent' | 'read' | 'failed' |
— | Delivery status under the bubble. |
typing |
boolean |
false |
Three animated dots instead of the text, labelled with the sender, e.g. “Ana Lima is typing”. |
as |
'li' | 'div' |
'li' |
Row element. |
class |
string |
— | Extra classes on the row. |
Variants
Every status, a link preview, an attachment and reactions:
Show codeHide code
<Message me status="sent">Sent</Message>
<Message me status="read">Read</Message>
<Message me status="failed">Failed</Message>States
- Typing — three dots, labelled for assistive tech; still under reduced motion.
Show codeHide code
<Message name="Ana Lima" typing><Avatar slot="avatar" name="Ana Lima" size="small" /></Message>Examples
A conversation with a day marker, and a composer under it. Composers are plain forms: a Textarea and a send Button.
- Today
Show codeHide code
<ol aria-label="Conversation" class="flex flex-col gap-4">
<li><Divider>Today</Divider></li>
<Message …>…</Message>
</ol>
<form class="flex items-end gap-2">
<Textarea label="Message" rows={2} class="flex-1" />
<Button type="submit" iconOnly aria-label="Send"><Send /></Button>
</form>Accessibility
- Put Messages in an
<ol>with anaria-label; each row is a list item, so screen readers announce position and count. - The sender is
<cite>and the time is<time datetime>. - Status glyphs carry screen-reader text (“Sent”, “Read”, “Failed to send”).
- The typing bubble is an image labelled with the sender, e.g. “Ana Lima is typing”; its dots stop moving under reduced motion.
- Bubble colours come from the hue tokens and keep AA in both themes.
Tokens
| Token | Used for |
|---|---|
--background-neutral-faded / --foreground-neutral |
Others’ bubbles |
--background-primary / --on-primary |
Your bubbles |
--border-primary |
Reply quote rule (others) |
--foreground-neutral-faded |
Time, status |
--foreground-critical |
Failed status |
Do / Don’t
- Do keep one Message per send; split long thoughts into several.
- Do show
statusonly on your own messages. - Don’t colour bubbles per person; the side and the avatar carry identity.
- Don’t hide actions behind hover only; put them in a menu reachable by keyboard.
Content
- Times are short (“9:41”, “Yesterday”); the full date belongs in
datetime. - Day markers in the list (“Today”, “Monday”) use a Divider.
Related
AvatarA user image, with an initials fallback derived from name.
TextareaA labeled multiline input, wired the same way as Input — label, hint, and error.
DividerA separator between content, horizontal or vertical.
TimelineA vertical list of events with a connecting line — activity log, history, changelog.