A conversation drawn as message groups: consecutive messages from one person within a few minutes gather under one avatar and name, their corners tightening where the bubbles meet so a run reads as one voice. The reader's messages sit on the right in the primary color, everyone else's on the left in one of three tones. Times slide out beside a bubble on hover or focus, the reader's latest message carries its delivery state (sending, sent, delivered, read), reactions sit under a bubble as chips, bare links become links, and a typing bubble of three dots joins the person's group. The whole log is one tab stop with arrow keys between messages.
The import and the props worth knowing about, in one place.
import { ChatBubble } from "@/components/beste/component/chat-bubble";
<ChatBubble
me="joni"
people={[
{ id: "joni", name: "Joni Mitchell" },
{ id: "miles", name: "Miles Davis", avatar: "/avatars/miles.jpg" },
]}
messages={[
{ id: "1", from: "miles", text: "Rehearsal moved to Thursday.", time: "2026-09-27T17:02:00Z" },
{ id: "2", from: "joni", text: "Works for me.", time: "2026-09-27T17:05:00Z", status: "read" },
]}
typing={["miles"]} // a three-dot bubble joins their group
onReact={(id, emoji) => console.log("React", id, emoji)} // makes reaction chips pressable
groupWithin={5} // minutes between messages in one group
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
/>Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Up / Down | Moves between messages once one is focused, showing its time. |
|---|---|
| Home / End | Jumps to the first or last message. |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
messages* | ChatMessage[] | β | |
people* | ChatPerson[] | β | Everyone who appears in `messages` or `typing`. |
me* | string | β | Id of the reader; their messages sit on the right. |
typing | string[] | β | Ids of people typing right now, shown as a bubble of three dots. |
groupWithin | number | β | Messages further apart than this, in minutes, start a new group. |
showNames | boolean | β | Show names above other people's groups. |
onReact | (messageId: string, emoji: string) => void | β | Called when a reaction chip is pressed. Without it the chips are read-only. |
formatTime | (date: Date) => string | β | How a message time reads. Runs on the client only, so time zones never split server and client. |
tone | "muted" | "outline" | "ghost" | β | |
size | "sm" | "default" | "lg" | β | |
className | string | β | |
aria-label | string | β |