Bubble
The message bubble surface for conversations: owns only the bubble itself (background/border/radius/max width + content), while avatar, name, time, and delivery state belong to the oas-message-row composition row. For AI assistants, support chats, IM conversations, etc.
Basic Usage
Default bubble
Content goes into the default slot; width fits content with an 80% container cap (override chain-wide via --oas-bubble-max-width).
Alignment (align)
Start / end sides
align="start" | "end" is implemented with logical layout (margin-inline-start: auto + text-align: end) — no physical-direction CSS.
Variants (variant)
Six semantic variants
The tinted surfaces of secondary/destructive mix theme semantic colors via color-mix() (theme-aware) and adapt automatically in dark mode; ghost lifts the 80% width cap for long streaming answers.
Typing (loading)
loading typing indicator
With the boolean loading attribute present, content switches to a three-dot typing indicator (the AI "typing" scenario) and the host element reflects aria-busy; the animation respects prefers-reduced-motion.
Reactions (reactions)
Emoji + count (side / align)
Click a reaction button; the received oas-reaction shows here.
reactions is a JSON array (each item { emoji, count?, active?, label? }, emoji required; an empty array/invalid JSON renders nothing). reactions-side controls top/bottom (default bottom; top places it above the bubble) and reactions-align overrides horizontal alignment (defaults to following the bubble align). Each reaction is a real button (keyboard reachable + focus ring + aria-pressed reflecting the active state): clicking it dispatches oas-reaction (detail { emoji, count, active, index }) — reaction data stays owned by the host, the component only dispatches intent.
Accessibility
- Direction is never conveyed by color/alignment alone: sender name and message text live in
oas-message-row's header/content, readable by screen readers. - The
loadingdots carryrole="status"with a localized accessible name ("Typing…"); the dots themselves arearia-hidden. - Bubbles are purely presentational (no tab stop); rich content (links/buttons) goes into the default slot and keeps native reachability.
API
oas-bubble
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
align | Direction: start (other party, default) / end (self) — logical-property alignment (align-self, RTL mirrored automatically); when set explicitly it wins over the inherited text-align reflection | — | — |
loading | Typing state (boolean presence): content switches to a three-dot typing indicator and the host reflects aria-busy (the AI "typing" scenario) | boolean | — |
reactions | Reaction bar as a JSON array; each item { emoji, count?, active?, label? } (emoji required). Empty array / invalid JSON renders nothing | — | — |
reactions-align | Horizontal alignment of the reaction bar: start / end; defaults to following the bubble align | — | — |
reactions-side | Vertical placement of the reaction bar: bottom (default, below the bubble) / top (above the bubble) | — | — |
Events
| Event | Description |
|---|---|
oas-reaction | Fired when a reaction is clicked; detail { emoji, count, active, index } (reaction data stays owned by the host) |
Slots
| Name | Description |
|---|---|
| default | Bubble content |
CSS Variables
| CSS Variable | Default |
|---|---|
--oas-bubble-max-width | 80% |
--oas-bubble-radius | var(--oas-radius-lg) |
Parts: ::part(bubble), ::part(content), ::part(typing), ::part(reactions) reaction strip / ::part(reaction) a single reaction button. align (start default / end) and variant (default / secondary / muted / outline / ghost / destructive) are pure CSS channels.