Bubble
The message surface, with variants and reactions
Hey there! what's up?
Hey! Want to see chat bubbles?
I can group messages, switch sides, and keep the whole thread easy to scan.
Sure. Hit me with your best demo.
Yes. You are reading a demo that is demoing itself. Very meta. Very on-brand.
No action yet.
A bubble is the surface one message wears. It is independent of Message: use
it for a reply, a quoted message, a suggestion or a notification. Message owns
the author, avatar, timestamp and row layout; Bubble owns the painted box.
Installation
nub add @gpuixui/componentsUsage
import {
Bubble,
BubbleAction,
BubbleActions,
BubbleContent,
} from "@gpuixui/components";
<Bubble variant="muted" align="end">
<BubbleContent>Roll it out to the whole team.</BubbleContent>
<BubbleActions label="Message actions">
<BubbleAction label="Copy" onClick={copy} />
</BubbleActions>
</Bubble>;Composition
Bubble
├── BubbleContent
├── BubbleActions
│ └── BubbleAction
└── BubbleReactionsBubbleGroup stacks consecutive bubbles from one sender:
BubbleGroup
├── Bubble group="first"
├── Bubble group="middle"
└── Bubble group="last"Variants
| Variant | Description |
|---|---|
default | The primary fill, usually the reader's own message. |
secondary | The neutral secondary fill. |
muted | A quiet supporting surface. |
tinted | A soft primary tint. |
outline | A bordered surface on the page fill. |
ghost | Unframed prose; it takes the whole row instead of 80%. |
destructive | A soft destructive surface for a failed turn or an error. |
A bubble is at most 80% of its row (ghost is 100%). Pass maxWidth to change
the cap.
Grouping
BubbleGroup tightens the gap to the theme's md (8px). Each bubble names its
place with group: first joins below, middle joins both sides, last
joins above and keeps a short tail on the sender's corner, and single is the
whole radius. The joined corner is the theme's sm step and the outer corners
keep xl, so a run reads as one column without losing its frame.
Shape
The surface is shadcn's: px-3 py-2 (12px by 8px), the body type role
(14px/20px), and the theme's xl corner. A bubble is at most 80% of its row
(ghost is 100%); pass maxWidth to change the cap.
Actions and reactions
BubbleActions is laid out even while hidden and fades in on pointer-over or
when one of its BubbleActions holds focus, so revealing it never moves the
bubble.
BubbleReactions is the pill on the bubble's edge: inset 12px from the
sender's side, a full radius, the muted fill and a page-fill ring around it so
it reads as cut out of the surface. It hangs a quarter of its height over the
bubble's bottom edge — translate-y-3/4's crossing, expressed as a negative
inset from inside the column — and the rest of the pill's box lays out below the
edge, so the next row cannot paint over it.
API
| Part | Renders | Props |
|---|---|---|
Bubble | the row: optional avatar, content column, 80% cap | variant?, align?, group?, maxWidth?, avatar?, className?, children |
BubbleContent | the framed surface | className?, children |
BubbleActions | a named group that reserves its height and fades in | label?, className?, children |
BubbleAction | one small ghost action, and the Button busy state | label (required), onClick, disabled?, className?, loading?, loadingLabel?, leading?, trailing?, reducedMotion? |
BubbleReactions | a named pill that hangs over the surface's edge | label (required), className?, children |
BubbleGroup | a tighter column | gap?, className?, children |
Edit this page on GitHubpackages/components/docs/bubble.mdx