Pho Design System

Message

One turn in a thread: the row that seats an avatar beside a column of header, Bubble, and footer, on the author’s side. It owns the row layout and nothing else — the surface is the bubble’s, the scrolling and the composer are Chat’s.

Is the number live yet?
2:47 PM
Yes — since this morning.
2:48 PM
Delivered.

Import

import { Message } from "@photon-ai/pho-ui/components/message";

Anatomy

Root takes align. Avatar seats an Avatar.Root, bottom-aligned with the bubble. Content places a Header (who) over the bubble, Time beside it, and a Footer (status) under it. Inbound is the time on the right of the bubble. Outbound is the time on the left, with Delivered or Failed under the bubble. align="end" mirrors the row for your own messages.

<Message.Root>
  <Message.Avatar>
    <Avatar.Root size="sm">…</Avatar.Root>
  </Message.Avatar>
  <Message.Content>
    <Message.Header>+1 (725) 699-0248</Message.Header>
    <Bubble.Root>
      <Bubble.Content>Who's on call this weekend?</Bubble.Content>
    </Bubble.Root>
    <Message.Time>9:12 AM</Message.Time>
  </Message.Content>
</Message.Root>

The sender over the bubble, in secondary ink — for a group, where the avatar alone does not say who. One-to-one threads leave it off.

AL
+1 (725) 699-0248
Who's on call this weekend?
9:12 AM
KN
+1 (540) 390-8722
Me until Sunday noon.
9:14 AM

Time sits beside the bubble, last-line aligned, in description ink. It stays in the slot and shows when the row is hovered or focused. Outbound Footer is the status under the bubble (Delivered, Failed). Inbound is the time alone. A failure keeps the same line and takes the error ink.

Two things.
The webhook signed. Delivery reports flow.
2:47 PM
Perfect.
2:49 PM
Failed. 30007.

Ghost

With a ghost bubble the header and footer lose their inset, so prose from an assistant lines up with its name.

Summarize this thread.
AI
Assistant
Three messages since Friday. The number went live at 2:47 PM; the first delivery report arrived a minute later; one send failed with 30007 (carrier filtered).
Just now

Props

Message.Root

Message.Group, Message.Avatar, Message.Content, Message.Header, Message.Time, Message.Footer take <div> attributes.

Best practices