Bubble
Displays framed conversational content, such as the messages in a chat thread
<sa-bubble-group class="w-full">
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>
Morning! Your Kyoto itinerary is ready — 12 to 19 April.
</sa-bubble-content>
</sa-bubble>
<sa-bubble align="BubbleAlign.End">
<sa-bubble-content>
That's great. Does it still include the Arashiyama day trip?
</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>
It does — the bamboo grove in the morning, then the Sagano railway at 14:00.
</sa-bubble-content>
</sa-bubble>
</sa-bubble-group>Usage
A bubble is composed of <sa-bubble> wrapping a single <sa-bubble-content>, optionally with a <sa-bubble-reactions> row. Stack bubbles inside a <sa-bubble-group>. Bubbles can also tbe used with Message inside of <sa-message-content>.
<sa-bubble-group>
<sa-bubble variant="..." align="...">
<sa-bubble-content>
...
</sa-bubble-content>
<sa-bubble-reactions side="..." align="...">
...
</sa-bubble-reactions>
</sa-bubble>
</sa-bubble-group>A bubble sizes itself to its content, up to 80% of the width of its container. The Ghost variant is the exception: it takes the full width, since it is not meant to read as a framed message.
The variant styling is applied to the <sa-bubble-content> inside the bubble rather than to <sa-bubble> itself, so <sa-bubble> stays a transparent positioning wrapper that the reactions row can be anchored to.
Examples
Variant
Set variant to pick the visual treatment. Default is the strongly emphasized bubble you would use for the current user's own messages, Secondary the neutral one for everyone else. Muted and Tinted step the emphasis down for supporting content, Outline drops the fill, Ghost removes the frame entirely, and Destructive marks an error or a failed action.
<sa-bubble variant="BubbleVariant.Default">
<sa-bubble-content>Could we add a second night in Hakone?</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>Of course — the ryokan has availability on the 16th.</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Muted">
<sa-bubble-content>Voyager Travel is typing...</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Tinted">
<sa-bubble-content>Your itinerary was updated 2 minutes ago.</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Outline">
<sa-bubble-content>Booking reference VYG-4821-KIX</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Ghost">
<sa-bubble-content>Conversation moved to your travel consultant.</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Destructive">
<sa-bubble-content>Message not delivered. Check your connection.</sa-bubble-content>
</sa-bubble>Align
Set align to BubbleAlign.End to move a bubble to the far side of the conversation, which is the usual way to distinguish outgoing messages from incoming ones. This works by aligning the bubble within its parent, so the bubbles need a <sa-bubble-group> (or another column-flex container) around them.
<sa-bubble variant="BubbleVariant.Secondary" align="BubbleAlign.Start">
<sa-bubble-content>
Your driver will meet you at Kansai Airport, arrivals hall B.
</sa-bubble-content>
</sa-bubble>
<sa-bubble align="BubbleAlign.End">
<sa-bubble-content>
Perfect, thank you.
</sa-bubble-content>
</sa-bubble>Group
<sa-bubble-group> stacks bubbles in a column with a tighter gap than you would normally put between separate messages, which is what makes a run of consecutive bubbles read as coming from one sender.
<sa-bubble-group>
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>Your e-tickets are attached to the itinerary.</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>Check-in opens 24 hours before departure.</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>Let me know if you'd like seats together.</sa-bubble-content>
</sa-bubble>
</sa-bubble-group>
<sa-bubble-group>
<sa-bubble align="BubbleAlign.End">
<sa-bubble-content>Yes please — two seats by the window.</sa-bubble-content>
</sa-bubble>
<sa-bubble align="BubbleAlign.End">
<sa-bubble-content>And a vegetarian meal for both of us.</sa-bubble-content>
</sa-bubble>
</sa-bubble-group>Reactions
<sa-bubble-reactions> renders a small pill that overlaps the edge of the bubble. Use side to put it on the top or bottom edge, and align to anchor it to the leading or trailing end.
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>
Upgraded you both to a garden-view room in Kyoto.
</sa-bubble-content>
<sa-bubble-reactions role="img" aria-label="Reactions: thumbs up, party popper">
<span>👍</span>
<span>🎉</span>
</sa-bubble-reactions>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>
The Sagano railway tickets are confirmed.
</sa-bubble-content>
<sa-bubble-reactions side="BubbleReactionsSide.Top" align="BubbleReactionsAlign.Start"
role="img" aria-label="Reactions: steam train">
<span>🚆</span>
</sa-bubble-reactions>
</sa-bubble>
<sa-bubble align="BubbleAlign.End">
<sa-bubble-content>
Booked — see you in April.
</sa-bubble-content>
<sa-bubble-reactions align="BubbleReactionsAlign.Start" role="img" aria-label="Reactions: red heart">
<span>❤️</span>
</sa-bubble-reactions>
</sa-bubble>Emoji on their own are announced inconsistently by screen readers, so give the reactions row a role="img" and an aria-label describing what the reactions are.
Link content
Use <sa-bubble-link-content> instead of <sa-bubble-content> to render the bubble surface as an <a>, making the whole bubble a link. It picks up the hover and focus styling of the bubble's variant. A run of them reads as a list of things the reader can open — documents, bookings, further reading.
<sa-bubble align="BubbleAlign.End">
<sa-bubble-content>
Could you send me the travel documents?
</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>
All three are ready:
</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Outline">
<sa-bubble-link-content asp-page="/Booking/Document" asp-route-id="e-ticket">
E-ticket — Cape Town to Osaka
</sa-bubble-link-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Outline">
<sa-bubble-link-content asp-page="/Booking/Document" asp-route-id="hotel-voucher">
Hotel voucher — Kyoto, 12 to 19 April
</sa-bubble-link-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Outline">
<sa-bubble-link-content asp-page="/Booking/Document" asp-route-id="transfer">
Airport transfer confirmation
</sa-bubble-link-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>
Worth a read before you fly:
</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Outline">
<sa-bubble-link-content href="https://www.japan.travel/" target="_blank" rel="noopener noreferrer">
Japan entry requirements
</sa-bubble-link-content>
</sa-bubble>The URL can be specified a couple of ways:
- You can use the
hrefproperty to specify any valid URL as per thehrefproperty of the anchor element. - You can use any of the attributes that are valid for specifying the URL for the ASP.NET Core Anchor Tag Helper, such as
asp-controller,asp-action,asp-page, etc. Please refer to the Anchor Tag Helper documentation for more examples.
Button content
Use <sa-bubble-button-content> to render the bubble surface as a <button>, for a bubble that acts rather than reads. Its most common job is offering the reader a set of replies to pick from, but it also covers the affordances around a thread — retrying a message that failed to send, pulling in the earlier part of the conversation.
<sa-bubble variant="BubbleVariant.Muted">
<sa-bubble-button-content>
Show 4 earlier messages
</sa-bubble-button-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Secondary">
<sa-bubble-content>
Your 14:00 Sagano railway seats are no longer available. How would you like to proceed?
</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Outline" align="BubbleAlign.End">
<sa-bubble-button-content>
Take the 16:30 departure
</sa-bubble-button-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Outline" align="BubbleAlign.End">
<sa-bubble-button-content>
Swap for a Hozugawa river cruise
</sa-bubble-button-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Outline" align="BubbleAlign.End">
<sa-bubble-button-content>
Cancel this activity
</sa-bubble-button-content>
</sa-bubble>
<sa-bubble align="BubbleAlign.End">
<sa-bubble-content>
Could you also move our dinner booking to 19:30?
</sa-bubble-content>
</sa-bubble>
<sa-bubble variant="BubbleVariant.Destructive" align="BubbleAlign.End">
<sa-bubble-button-content>
Not delivered. Tap to retry.
</sa-bubble-button-content>
</sa-bubble>Prefer these over attaching a click handler to a plain <sa-bubble-content>: rendering a real <a> or <button> is what makes the bubble reachable by keyboard and announced as interactive.
API Reference
<sa-bubble>
Renders a <div> element, forwarding any global attributes.
Prop
Type
<sa-bubble-content>
Renders a <div> element holding the message content, forwarding any global attributes.
<sa-bubble-link-content>
Renders an <a> element in place of <sa-bubble-content>, making the whole bubble a link.
Routing attributes
The link bubble content also accepts the same routing attributes as the ASP.NET Core Anchor Tag Helper for generating the href. Supply either an href or these attributes — not both.
Prop
Type
<sa-bubble-button-content>
Renders a <button> element in place of <sa-bubble-content>, making the whole bubble activatable. The type defaults to button so a bubble inside a form does not submit it; set type explicitly to override that.
<sa-bubble-reactions>
Renders a <div> element anchored to an edge of the bubble, forwarding any global attributes.
Prop
Type
<sa-bubble-group>
Renders a <div> element that stacks bubbles in a column, forwarding any global attributes.