Components
Bubble
Displays conversational content in a message bubble. Supports variants, alignment, grouping, reactions, and collapsible content.
Source code
Click to see the source code for this component on GitHub. Feel free to copy it and adjust it for your own use.
Installation
Usage
The Bubble component displays framed conversational content. Use it for chat text, short structured output, quoted replies, suggestions, and reactions.
For full-featured chat interfaces, place avatars, names, timestamps, metadata, and message-level actions in the surrounding container. Bubble is intentionally scoped to the bubble surface.
Anatomy
Bubble Anatomy.vue
<template>
<UiBubbleGroup>
<UiBubble>
<UiBubbleContent />
<UiBubbleReactions />
</UiBubble>
<UiBubble>
<UiBubbleContent />
</UiBubble>
</UiBubbleGroup>
</template>
Use UiBubbleGroup to group consecutive bubbles from the same sender. Set align on each UiBubble, not on the group.
Features
- Seven visual variants, from a strong primary bubble to unframed ghost content
- Start and end alignment for sender and receiver bubbles
- Reactions that anchor to the bubble edge with configurable side and alignment
- Bubbles size to their content, up to 80% of the container width
- Polymorphic content via
asoras-childfor link and button bubbles - Every part renders through
Primitive, soas/as-childand Vueclassoverrides work on any part
Examples
Variants
Use variant to change the visual treatment of the bubble.
A bubble sizes to its content, up to 80% of the container width. The ghost variant removes the max-width so assistant text and rich content can span the full row.
| Variant | Description |
|---|---|
default | A strong primary bubble, usually for the current user. |
secondary | The standard neutral bubble for conversation content. |
muted | A lower-emphasis bubble for quiet supporting content. |
tinted | A subtle primary-tinted bubble. |
outline | A bordered bubble for secondary or rich content. |
ghost | Unframed content for assistant text or rich content. |
destructive | A destructive bubble for error or failed actions. |
Alignment
Use align on UiBubble to align the bubble to the start or end of the conversation.
| align | Description |
|---|---|
start | Align the bubble to the start of the conversation. |
end | Align the bubble to the end of the conversation. |
Bubble Group
Use UiBubbleGroup to group consecutive bubbles from the same sender. Note the align prop should be set on the UiBubble component itself, not the UiBubbleGroup component.
Links and Buttons
Use as-child to merge UiBubbleContent styling and attributes onto a link or button passed through its default slot.
Reactions
Use UiBubbleReactions for bubble reactions. You can use it to display reactions or quick action buttons. Use side and align to position the row — side="top" anchors it to the upper edge. Reactions overlap the bubble edge, so leave vertical space between rows — the examples below use a larger gap for this reason.
Show More / Collapsible
Long bubble content can be composed with Collapsible to allow for a show more or show less interaction. Use the UiCollapsibleTrigger component to trigger the collapsible content.
Tooltip
Wrap a bubble reaction in a Tooltip to reveal metadata on hover, such as when a message was read.
Popover
Pair a bubble reaction with a Popover to surface more information on demand, such as the full error message for a failed action.
Accessibility
UiBubble renders the presentational message surface. Keep conversation-level semantics on the surrounding container and follow the guidelines below.
Labeling Reactions
Reactions render as a row of emoji. A screen reader reads each glyph with no context, and counters like +8 are announced as "plus eight". Group the row as a single image with a descriptive aria-label so it announces once. role="img" also hides the individual emoji from assistive tech, so no aria-hidden is needed.
<template>
<UiBubbleReactions role="img" aria-label="Reactions: thumbs up, fire, and 8 more">
<span>👍</span>
<span>🔥</span>
<span>+8</span>
</UiBubbleReactions>
</template>
When reactions are interactive, render buttons instead and give icon-only buttons an aria-label.
<template>
<UiBubbleReactions>
<UiButton aria-label="Thumbs up" variant="secondary" size="icon-xs">
<Icon name="lucide:thumbs-up" />
</UiButton>
</UiBubbleReactions>
</template>
Interactive Bubbles
When a bubble is clickable, pass a real <button> or <a> through UiBubbleContent with as-child so it is focusable and exposes the correct role. UiBubbleContent ships a visible focus ring for interactive elements, and the accessible name comes from the bubble text. No extra label is needed.
<template>
<UiBubble variant="muted" align="end">
<UiBubbleContent as-child>
<button type="button" @click="onReply">I forgot my password</button>
</UiBubbleContent>
</UiBubble>
</template>
Meaning Beyond Color
Bubble variants signal role and tone with color. Pair them with text, alignment, or icons so meaning is not conveyed by color alone. For a destructive bubble, keep the error context in the message text rather than relying on the color treatment.
API Reference
All Bubble parts render through Primitive. Use as to choose another element, or as-child to merge the component's attributes and styles onto the single element or component in its default slot.
Bubble
The root bubble wrapper.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "secondary" | "muted" | "tinted" | "outline" | "ghost" | "destructive" | "default" | The bubble visual treatment. |
align | "start" | "end" | "start" | The inline alignment of the bubble. |
as | PrimitiveProps["as"] | "div" | Element or component to render. |
as-child | boolean | false | Render the default slot as the root and merge props onto it. |
class | HTMLAttributes["class"] | - | Additional classes to apply to the root element. |
BubbleContent
The bubble content wrapper.
| Prop | Type | Default | Description |
|---|---|---|---|
as | PrimitiveProps["as"] | "div" | Element or component to render. |
as-child | boolean | false | Render the default slot as the root and merge props onto it. |
class | HTMLAttributes["class"] | - | Additional classes to apply to the content element. |
BubbleReactions
Displays overlapped reactions for a bubble.
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top" | "bottom" | "bottom" | The side of the bubble to anchor the reactions. |
align | "start" | "end" | "end" | The inline alignment of the reactions. |
as | PrimitiveProps["as"] | "div" | Element or component to render. |
as-child | boolean | false | Render the default slot as the root and merge props onto it. |
class | HTMLAttributes["class"] | - | Additional classes to apply to the reaction row. |
BubbleGroup
Groups consecutive bubbles from the same sender.
| Prop | Type | Default | Description |
|---|---|---|---|
as | PrimitiveProps["as"] | "div" | Element or component to render. |
as-child | boolean | false | Render the default slot as the root and merge props onto it. |
class | HTMLAttributes["class"] | - | Additional classes to apply to the group root. |