Glin UI
Primitive / Moleculebeta

Bubble

Chat bubble surface with default, muted, accent and glass variants, optional tail and grouped spacing.

Edit on GitHub
Hi, your order shipped this morning.
It should arrive by Thursday.
Great, can I change the address?
It is the old one on Pine Street.
Yes, until it reaches the depot. Sending a link now.

Installation

Install from
pnpm dlx @glinui/cli@latest add bubble

Prefer the package?

Usage

Inside a chat screen

Message wraps Bubble; this is the full screen.

Q3 revenue review

Glin assistant, 3 sources

Online
MK
Summarize how Q3 went compared with Q2.
q3-revenue.csv47 KB
board-notes.pdf1.1 MB
G
Revenue grew 12% quarter over quarter, driven mostly by the Pro plan. Churn stayed flat at 1.8%, so the gain came from expansion rather than new logos.
MK
Which regions grew fastest?
G
Europe led with 19% growth, followed by North America at 11%. APAC was flat after the pricing change in August.
G
Thinking...
import { ArrowsClockwise, Paperclip, ThumbsDown, ThumbsUp } from "@phosphor-icons/react"
import {
Attachment, Badge, Heading, Message, MessageAction, MessageActions, MessageAvatar, MessageContent,
MessageCopyAction, MessageScroller, PromptInput, StreamingText, Text, Thinking
} from "@glinui/ui"
const reply = "Revenue grew 12% quarter over quarter, driven mostly by the Pro plan. Churn stayed flat at 1.8%, so the gain came from expansion rather than new logos."
export function ChatScreen() {
return (
<div className="flex h-[34rem] w-full max-w-2xl flex-col overflow-hidden rounded-2xl border border-[var(--line-soft)] bg-[var(--surface-1)] text-left">
<header className="flex items-center justify-between gap-3 border-b border-[var(--line-soft)] px-4 py-3">
<div className="flex flex-col">
<Heading level={2} size="sm">Q3 revenue review</Heading>
<Text size="sm" variant="muted">Glin assistant, 3 sources</Text>
</div>
<Badge tone="success" variant="soft">Online</Badge>
</header>
<MessageScroller label="Conversation" className="min-h-0 flex-1">
<Message role="user">
<MessageAvatar fallback="MK" alt="" />
<MessageContent>
<div className="flex flex-col gap-2">
<span>Summarize how Q3 went compared with Q2.</span>
<div className="flex flex-wrap gap-2">
<Attachment name="q3-revenue.csv" size={48210} />
<Attachment name="board-notes.pdf" size={1203400} />
</div>
</div>
</MessageContent>
</Message>
<Message role="assistant">
<MessageAvatar fallback="G" alt="" />
<MessageContent
actions={
<MessageActions>
<MessageCopyAction value={reply} />
<MessageAction label="Regenerate"><ArrowsClockwise /></MessageAction>
<MessageAction label="Good response" pressed><ThumbsUp /></MessageAction>
<MessageAction label="Bad response"><ThumbsDown /></MessageAction>
</MessageActions>
}
>
<div className="flex flex-col gap-2">
<Thinking active={false} doneLabel="Thought for 4 seconds">Compared monthly totals, then split growth into new and expansion revenue.</Thinking>
<span>{reply}</span>
</div>
</MessageContent>
</Message>
<Message role="user">
<MessageAvatar fallback="MK" alt="" />
<MessageContent>Which regions grew fastest?</MessageContent>
</Message>
<Message role="assistant">
<MessageAvatar fallback="G" alt="" />
<MessageContent>
<StreamingText text="Europe led with 19% growth, followed by North America at 11%. APAC was flat after the pricing change in August." speed={30} />
</MessageContent>
</Message>
<Message role="assistant">
<MessageAvatar fallback="G" alt="" />
<MessageContent><Thinking /></MessageContent>
</Message>
</MessageScroller>
<div className="border-t border-[var(--line-soft)] p-3">
<PromptInput
placeholder="Ask a follow up"
maxLength={500}
onSubmit={(value) => console.log(value)}
actions={<MessageAction label="Attach file"><Paperclip /></MessageAction>}
/>
</div>
</div>
)
}

Variants

Default surface
Muted
Accent
Glass
import { Bubble } from "@glinui/ui"
export function Demo() {
return (
<div className="flex flex-col items-start gap-2">
<Bubble>Default surface</Bubble>
<Bubble variant="muted">Muted</Bubble>
<Bubble variant="accent">Accent</Bubble>
<Bubble variant="soft">Glass</Bubble>
</div>
)
}

Variants

Every vocabulary variant on the default tone. Omit variant to follow the ambient design style.

glinr
solid
plain
soft
outline
ghost
gradient
import { Bubble } from "@glinui/ui"
export function BubbleVariantsDemo() {
return (
<div className="flex flex-wrap items-start gap-3">
<Bubble variant="glinr">glinr</Bubble>
<Bubble variant="solid">solid</Bubble>
<Bubble variant="plain">plain</Bubble>
<Bubble variant="soft">soft</Bubble>
<Bubble variant="outline">outline</Bubble>
<Bubble variant="ghost">ghost</Bubble>
<Bubble variant="gradient">gradient</Bubble>
</div>
)
}

Glass (opt-in)

Glass is opt-in and needs a backdrop behind it. Switch the preview stage to Vivid or Photo to see the frosted surface.

glass
import { Bubble } from "@glinui/ui"
export function BubbleGlassDemo() {
return (
<Bubble variant="glass">glass</Bubble>
)
}

Accessibility

  • Renders a plain div with no implicit role, so content stays readable inside a log region.
  • Accent text uses the accent-foreground token for AA contrast in light and dark.
  • Long words wrap instead of overflowing.

Reduced Motion

Bubble has no motion of its own.

API Reference

PropTypeRequiredDefaultDescription
variantBubbleVariantNoambient (glinr)Surface variant. Omit to follow the ambient design style (glinr by default, plain for minimal, glass for glass).
toneSurfaceToneNoneutralColour tone for the vocabulary variants.
align"start" | "end"NostartWhich side the bubble sits on. Controls tail and group corners.
tailbooleanNofalseSquare the corner nearest the sender.
groupedbooleanNofalseTighten the aligned edge for stacked bubbles.

Source

Import directly from the package or browse the source on GitHub. Click any file to view it.

Import

import { Bubble } from "@glinui/ui"

Source Files

Dependencies

@glinui/uiclass-variance-authority

Generated API Snapshot

Beta

Auto-extracted from TypeScript source in packages/ui/src/components/bubble.tsx. This section is in beta and may lag behind hand-curated docs. Regenerate with pnpm --filter @glinui/docs api:generate.

Generated: 2026-10-08T01:41:21.546Z · Full index: /docs/api-metadata

Primary Props Type

BubbleProps

BubbleProps

PropTypeRequiredDefaultDescription
align"start" | "end"No--
groupedbooleanNofalseTightens the aligned edge so stacked bubbles read as one group.
tailbooleanNofalseSquares the corner nearest the avatar to point at the sender.
toneSurfaceToneNo--
variantBubbleVariantNo-Visual variant. Omit for the ambient design style (glinr: raised ringed bubble; plain: flat bordered bubble). Vocabulary: glinr, solid, plain, soft, outline, ghost, gradient, glass. `accent` is solid + accent tone, `muted` is soft.