iMessage UIv0.1.0

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.

Riley
yo did you call the dealer back
they had the one you wanted
what's their number so i can call
bet, calling now
Read
"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

Riley
LETS GOOO 🏎️
deposit's down 🔑
Delivered
🎉🎉🎉
"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

PropTypeDefaultDescription
text*stringMessage 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.
tailbooleantrueRender the tail curl (only shown on solo/last).
senderNamestringShown above first/solo received bubbles.
avatarAvatarInfoShown beside last/solo received bubbles.
receipt"delivered" | "read"Receipt below last/solo sent bubbles.
reactionsReaction[]Tapbacks, grouped by kind with a count badge.
hideAvatarbooleanfalseSuppress the avatar gutter (1-on-1 screenshot mode).
isNewlySentbooleanfalsePlay the one-shot iMessage send spring.
classNamestringExtra 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.