# Message Bubble

Chat bubbles in six styles with grouping, swipe-to-reply and long-press actions. Drag the thread to reveal times, hold a message to react, and watch read ticks update in place.

> Primitive · Pro · Data Display — React Native, Expo Go incompatible (dev build required).

## Install

```bash
npx @lumioui/cli add pro/message-bubble
```

## Import

```tsx
import { MessageBubble, MessageBubbleGroup } from "@/components/ui/message-bubble/message-bubble";
```

## Variants

- `chat` — Chat: `npx @lumioui/cli add pro/message-bubble-chat`
- `variants` — Support thread: `npx @lumioui/cli add pro/message-bubble-variants`

## Props

### MessageBubble

| Prop | Type | Notes |
| --- | --- | --- |
| `variant?` | `MessageBubbleVariant` | Bubble style. Default "soft". |
| `align?` | `MessageBubbleAlign` | Which side. Default "start". |
| `animateIn?` | `boolean` | Play an entrance animation when mounted. Default false. |
| `timestamp?` | `string` | Timestamp shown inside the bubble, next to the delivery ticks. |
| `time?` | `string` | Time revealed when the thread is swiped left (MessageBubbleGroup). |
| `sender?` | `string` | Sender name — exposed to screen readers, not rendered. |
| `onPress?` | `() => void` | Press handler — bubbles can be tappable (e.g. retry a failed send). |
| `onReply?` | `() => void` | Swipe right to reply. Commits on release past the line. |
| `onLongPress?` | `() => void` | Plain long-press callback (lift + your own UI). Ignored when the  built-in reactions / actions are enabled. |
| `sameAsPrev?` | `boolean` | Previous bubble is from the same sender — tightens the joined corner.  Inferred inside MessageBubbleGroup. |
| `sameAsNext?` | `boolean` | Next bubble is from the same sender. Inferred inside MessageBubbleGroup. |
| `tail?` | `boolean` | Draw the tail. Inferred inside MessageBubbleGroup (last of a run, solid  and soft only); off by default outside one. |
| `tailColor?` | `string` | Tail colour when you restyle the bubble's fill with className. |
| `enableSwipeReply?` | `boolean` | Enable swipe-to-reply. Default true when onReply is set. |
| `status?` | `MessageBubbleStatus` | Delivery state — swaps in place: sending dots → sent → delivered → read.  "sending" also holds the fill dim; "failed" flickers once. |
| `sendFrom?` | `MessageBubbleOrigin` | Composer text rect (`measureInWindow`) the words lift out of. Mount only. |
| `reaction?` | `string | null` | Your reaction (controlled). Enables the long-press reaction bar + chips. |
| `defaultReaction?` | `string | null` | Your initial reaction (uncontrolled). |
| `onReact?` | `(emoji: string | null) => void` | Fires when your reaction changes (null = taken back). |
| `reactionCounts?` | `Record<string, number>` | Everyone else's reactions, by emoji. |
| `reactionSet?` | `ReactionOption[]` | Emojis offered in the bar. |
| `onCopy?` | `() => void` | Adds "Copy" to the long-press menu. |
| `onDelete?` | `() => void` | Adds "Delete" to the long-press menu. |
| `actions?` | `ReactionAction[]` | Extra long-press menu rows. |
| `className?` | `string` | — |
| `textClassName?` | `string` | — |
| `children?` | `React.ReactNode` | — |

### MessageBubbleGroup

| Prop | Type | Notes |
| --- | --- | --- |
| `spacing?` | `"compact" | "default"` | Spacing between bubbles. Default "compact". |
| `revealTimes?` | `boolean` | Swipe the thread left to reveal each bubble's `time`. Default true. |
| `className?` | `string` | — |
| `children?` | `React.ReactNode` | — |

## Icons rendered

- `copy` — /icons.html?i=copy
- `trash` — /icons.html?i=trash

Source: https://lumioui.com/components/message-bubble