Components
ChatBubble
The high-level message bubble: grouping-aware tails, avatar gutter, sender names, read receipts, big-emoji rendering and tapback reactions. This is the component the group-chat simulator, message board and intake bot are built from.
"use client";
import { ChatBubble, IMessageScreen } from "imessage-ui";
import type { AvatarInfo } from "imessage-ui";
const RILEY: AvatarInfo = { initial: "R", gradient: ["#FF9FB2", "#E0506E"] };
export default function ConversationDemo() {
return (
<IMessageScreen className="w-full max-w-sm rounded-2xl p-4">
<ChatBubble variant="received" text="yo did you call the dealer back" position="first" senderName="Riley" avatar={RILEY} />
<ChatBubble variant="received" text="they had the one you wanted" position="last" avatar={RILEY} />
<ChatBubble variant="sent" text="what's their number so i can call" position="first" />
<ChatBubble variant="sent" text="bet, calling now" position="last" receipt="read" />
</IMessageScreen>
);
}position drives grouping: first/middle messages tuck their corners, only last/solo get the tail, avatars sit beside the last bubble of a run, sender names above the first.
Usage
import { ChatBubble, IMessageScreen } from "imessage-ui";
<IMessageScreen>
<ChatBubble variant="received" text="hey" senderName="Riley" />
<ChatBubble variant="sent" text="hey yourself" receipt="read" />
</IMessageScreen>Examples
Receipts, reactions & big emoji
"use client";
import { ChatBubble, IMessageScreen } from "imessage-ui";
export default function ReactionsDemo() {
return (
<IMessageScreen className="w-full max-w-sm rounded-2xl p-4 pt-8">
<ChatBubble
variant="received"
text="LETS GOOO 🏎️"
senderName="Riley"
avatar={{ initial: "R", gradient: ["#FF9FB2", "#E0506E"] }}
reactions={[{ kind: "heart" }, { kind: "heart", by: "devon" }]}
/>
<ChatBubble
variant="sent"
text="deposit's down 🔑"
receipt="delivered"
reactions={[{ kind: "like" }]}
/>
<ChatBubble variant="sent" text="🎉🎉🎉" />
</IMessageScreen>
);
}reactions stack as laid tapbacks on the bubble corner; 1–3 emoji render without a bubble, exactly like iMessage.
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
| text* | string | — | Message text. 1–3 emoji render bubble-less (big-emoji mode). |
| variant* | "sent" | "received" | — | Blue right-side bubble or gray left-side bubble. |
| position | "solo" | "first" | "middle" | "last" | "solo" | Position within a run of messages from the same sender — drives tails, avatar and sender-name visibility. |
| tail | boolean | true | Render the tail curl (only shown on solo/last). |
| senderName | string | — | Shown above first/solo received bubbles. |
| avatar | AvatarInfo | — | Shown beside last/solo received bubbles. |
| receipt | "delivered" | "read" | — | Receipt below last/solo sent bubbles. |
| reactions | Reaction[] | — | Tapbacks, grouped by kind with a count badge. |
| hideAvatar | boolean | false | Suppress the avatar gutter (1-on-1 screenshot mode). |
| isNewlySent | boolean | false | Play the one-shot iMessage send spring. |
| className | string | — | Extra classes on the row. |
Accessibility
Reactions render as decorated SVGs with their kind as text alternative; bubbles are plain text nodes, so screen readers read the thread naturally.