Theme studio

Design a theme, preview it live, then export it. Saved in this browser.

Quick picks #10b981
Generated scale
50100200300400500600700800900
Some text is below AA

MessageBubble

  • Stable
  • WCAG 2.2 evidence
  • RTL

One chat message: Direction (incoming, outgoing) x Type (text, reply, file, image) x Group (single, continued), with sender name and avatar, time, an edited mark and read ticks. Accessibility: the reading order is name, quoted message, content, then edited mark, time and status (WCAG 1.3.1). The sender's name is read even where it is hidden (continued, outgoing). Ticks and icons are decorative with text alternatives (1.1.1); delivery state is a shape and a text, never colour only (1.4.1). Text colours meet 4.5:1 in Light and Dark. Text wraps and keeps line breaks (1.4.10, 1.4.12). Logical layout: the sides and the tail corner mirror in right-to-left. Presentational: renders in React Server Components. Consumer duties: render the conversation as a list or a role="log" region; a meaningful alt on images; formatted times; the translated editedLabel, statusLabel and downloadLabel; say "You" (or similar) as name on outgoing messages if screen reader users need it.

import { MessageBubble } from "@nexera-ui/react";
Loading example…
5
examples
19
props
5
live controls
1
platform
8
WCAG criteria
5
blocks use it

Try every prop. Copy the code.

Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.

Loading…
children
direction
group
isEdited
status
Generated code
import { MessageBubble } from "@nexera-ui/react";

<MessageBubble />

Examples 4

The same examples as Storybook, rendered live. Open Code to copy one.

Conversation

A short conversation in a role="log" list: a run of incoming messages, a reply, a file and read ticks.

Loading example…

Image with caption

An image with a caption; the frame shrinks with the container and keeps its aspect ratio.

Loading example…

Long content

Long words, links and line breaks wrap inside the bubble; the bubble never overflows a narrow container.

Loading example…

Right to left

Right-to-left: incoming messages sit on the right, outgoing ones on the left, and the tail corner mirrors.

Loading example…

Props 19

Press "Try it" on a card to load that prop into the playground.

19 props shown

childrenNexera
ReactNode

The message. With type="image" it is the caption under the image. Line breaks typed by the author are kept; long words wrap.

Default –
directionNexera
"incoming" | "outgoing"

Who sent it. incoming sits at the inline start on bg/sunken; outgoing at the inline end on brand/primary. Sides swap in right-to-left.

Default incoming
typeNexera
"text" | "reply" | "file" | "image"

Content: plain text; a reply with the quoted message (quote, quoteAuthor) above the text; a file card (fileName, fileDetails, fileHref); or an image (image) with an optional caption (children).

Default text
groupNexera
"single" | "continued"

Position in a run of messages from the same person. single shows the sender's name and avatar; continued hides them (the name stays available to screen readers) and keeps the avatar's space so bubbles line up.

Default single
nameNexera
string

Sender's name. Shown above incoming single messages; otherwise it is visually hidden but read first, so every message says who wrote it (WCAG 1.3.1).

Default –
avatarNexera
ReactNode

Sender's avatar: pass <Avatar size="md" isDecorative... />; it is decorative because the name is given. Shown on incoming single messages; continued messages keep a 32 px space. Pass it on every incoming message of a conversation so the bubbles line up. Ignored on outgoing messages.

Default –
timeNexera
ReactNode

Time sent, formatted for the reader's locale.

Default –
dateTimeNexera
string

Machine-readable time of time (ISO 8601). When set, the time is a <time> element.

Default –
isEditedNexera
boolean

Show the "edited" mark.

Default false
editedLabelNexera
string

Text of the edited mark. Translate it for your locale.

Default edited
statusNexera
"sent" | "read"

Delivery ticks of an outgoing message: read draws two ticks, sent one. The ticks differ in shape, not colour, and carry a text alternative (WCAG 1.1.1, 1.4.1). Not shown when omitted.

Default –
statusLabelNexera
string

Text alternative of the status ticks. Translate it for your locale.

Default "Sent" or "Read"
quoteNexera
ReactNode

Quoted message of a reply. type="reply" only.

Default –
quoteAuthorNexera
ReactNode

Author of the quoted message. type="reply" only.

Default –
fileNameNexera
ReactNode

File name. type="file" only.

Default –
fileDetailsNexera
ReactNode

File type and size. type="file" only.

Default –
fileHrefNexera
string

Download URL. When set, the file card is a download link with the download icon, keyboard focusable with a visible focus ring (WCAG 2.1.1, 2.4.7). type="file" only.

Default –
downloadLabelNexera
string

Visually hidden text that starts the download link's name ("Download Contract 2026.pdf"; WCAG 2.4.4). Translate it.

Default Download
imageNexera
ReactNode

The image of type="image": pass an <img> with a meaningful alt (WCAG 1.1.1). It fills the frame, which shrinks with the container and keeps the Figma aspect ratio.

Default –

* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.

Accessible by default.

Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.

WCAG 2.2 evidence

6 direct · 2 supporting
  • 1.1.1Non-text ContentLevel A · tested directly
  • 1.3.1Info and RelationshipsLevel A · tested directly
  • 1.4.1Use of ColorLevel A · tested directly
  • 1.4.10ReflowLevel AA · supporting test
  • 1.4.12Text SpacingLevel AA · supporting test
  • 2.1.1KeyboardLevel A · tested directly
  • 2.4.4Link Purpose (In Context)Level A · tested directly
  • 4.1.2Name, Role, ValueLevel A · tested directly

Fits any width.

Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.

0 px · drag the corner

Styling hooks

Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.

Usage
<MessageBubble className="shadow-sm" />

Used in blocks

Related components