Message
A chat-style message bubble with sent/received variants and iOS-tapback-style reactions overlapping the bubble corner, a MessageReactions max/+N overflow stack like AvatarGroup, plus a source-citation use case for LLM responses.
Installation
npx dafink-ui add messageDemos
Media messages
Message renders whatever you pass as children. A compact AudioPlayer drops straight into the default bubble; its controls pick up the bubble's own text color automatically, no extra props needed. For content with its own visual chrome, like an image, pass bubble={false} so it isn't nested inside a second colored box.
Composition
Props
| Name | Type | Default | Description |
|---|---|---|---|
| variant | 'sent' | 'received' | 'received' | 'sent' right-aligns the bubble in brand fill; 'received' left-aligns it in a neutral surface tint. |
| avatar | ReactNode | - | Optional avatar rendered beside the bubble. |
| bubble | boolean | true | Set false to render children without the bubble background/padding, for content that supplies its own chrome (an image, an AudioPlayer) so it isn't nested in a second colored box. |
| className | string | '' | Additional CSS classes merged onto the root row. |
| children | ReactNode | - | The message content. A MessageReactions child is detected and extracted automatically; it can appear anywhere inside. |
Accessibility
Message itself is a non-interactive layout wrapper with no focus model. Its only focusable parts are MessageReaction chips, each rendered as a real <a> (when href is set) or <button type="button">, so each is an independent Tab stop in normal DOM order β reachable and activatable with native semantics (Enter for both, Space for buttons) β rather than a roving-tabindex composite, so no arrow-key navigation is implied between chips. The surrounding MessageReactions cluster is role="group" with an aria-label (default "Reactions"), and the "including yours" active state is always backed by a computed aria-label, border, fill, and checkmark icon, never color alone.