Skip to content
Alea0.1
Pro
  1. Alea
  2. Components
  3. Data display
  4. Chat

Data display

Chat

Conversations: messages in bubbles or plain, runs from the same author, day separators, a New messages line, delivery states, reactions, thread links, hover actions and a typing indicator.

import { MessageList, ChatMessage, ReactionBar, TypingIndicator } from '@alea/ui';

Examples

Conversation

A MessageList with day separators, runs from the same author, a New messages line, delivery states, reactions and a thread link. Send a message to see it follow the newest one.

Ana Rivas
Morning! The new tokens are in the Figma file.
Dark and light both pass AA now.
You
Great, I will update the docs today.
Read
Bruno Díaz
Can someone review the Modal page?
The scrolling example needs a second look on phones.
Ana Rivas is typing

Message, reactions and typing on their own

ChatMessage in the bubble and the plain look, a failed message, ReactionBar with the picker, and TypingIndicator for one, two or many people.

Carla Mendes
Shipping the release notes now.
edited
You
This one did not go through.
Not sent
Dario Silva
Plain messages read like a channel: no bubbles, full width.
Ana is typing
Ana and Bruno are typing
3 people are typing

Tokens

The design tokens this component reads, with their value in the current theme. Override any of them to restyle it.

Color

  • --alea-border…
  • --alea-focus…
  • --alea-status-danger…
  • --alea-text-muted…

Space

  • --alea-space-1…
  • --alea-space-2…
  • --alea-space-3…
  • --alea-space-4…
  • --alea-space-5…

Radius

  • --alea-radius-md…

Type

  • --alea-font-family-body…
  • --alea-font-size-xs…
  • --alea-font-weight-semibold…

Props

MessageList props

A conversation: day separators (Today, Yesterday, a date), runs from the same author, a New messages line, a typing indicator, and scrolling that follows new messages. A log region, so screen readers hear new messages as they arrive.

PropTypeDefaultDescription
messagesrequiredChatItem[]-The messages, oldest first.
aria-labelstring-Name for screen readers. Default "Messages".
classNamestring-Extra class names.
firstUnreadIdstring-Id of the first unread message: a "New messages" line shows above it.
groupMinutesnumber5Messages from the same author within this many minutes form a run (no repeated avatar and name). Default 5.
heightstring | number420Height of the scrolling list; it starts at the newest message and follows new ones while you are at the bottom.
onOpenThread((messageId: string) => void)-Called when a thread link is pressed.
onReact((messageId: string, emoji: string) => void)-Called when a reaction is toggled on a message.
renderActions((m: ChatItem) => ReactNode)-Extra actions per message, shown on hover and focus.
typingstring[]-Who is typing, shown at the end.
variant"bubble" | "plain"'bubble'bubble (default) or plain.

ChatMessage props

One message in a conversation: avatar and name (hidden inside a run), a bubble or plain text, time, delivery state, edited, reactions, a thread link and hover actions.

PropTypeDefaultDescription
authorrequiredstring-Who wrote it.
childrenrequiredReactNode-The message: text, or anything (images, files, cards).
actionsReactNode-Actions that show on hover and focus: reply, react, more (small IconButtons).
avatarSrcstring-Their photo.
classNamestring-Extra class names.
isEditedboolean-Marks it as edited.
isGroupedboolean-Part of a run from the same author: hides the avatar and the name.
isOwnboolean-Written by the current person: on the end side, in the accent bubble.
onOpenThread(() => void)-Opens the thread.
onReact((emoji: string) => void)-Called when a reaction is toggled; with it, the reactions get an add button.
reactionsReaction[]-Reactions under the bubble.
replyCountnumber-Number of replies in its thread, shown as a link.
status"sending" | "sent" | "delivered" | "read" | "failed"-Delivery state for own messages: sending, sent, delivered, read or failed.
timeDate-When it was sent: shown as a short time, with the full date on hover.
variant"bubble" | "plain"'bubble'bubble (default) or plain (no bubble, full width, like a channel).

ReactionBar props

Emoji reactions under a message or a comment: each is a toggle with its count, and the add button opens an EmojiPicker.

PropTypeDefaultDescription
onTogglerequired(emoji: string) => void-Called when someone toggles a reaction (an existing one, or a new one from the picker).
reactionsrequiredReaction[]-The reactions so far.
allowAddbooleantrueShows the add button that opens the emoji picker. Default true.
classNamestring-Extra class names.
size"sm" | "md"'md'sm (24 px) or md (28 px, default).

TypingIndicator props

"Ana is typing" with three bouncing dots. Announced politely once when it appears; the dots are decoration and stop with reduced motion.

PropTypeDefaultDescription
namesrequiredstring[]-Who is typing. Empty hides it.
classNamestring-Extra class names.

Specs

Generated from the source: the variants in the types, the states and tokens in the CSS, and the motion patterns that apply. The grids render the real component in both themes; the numbers are measured from the page.

MessageList

Variants
variantbubbleplain
States
Keyboard focus
Dark and light
Every color comes from theme tokens, so it follows data-theme (and presets like Graphite) on the page or any wrapper. Contrast is checked in both themes.
Styling hooks
.alea-msglist.alea-msglist-day.alea-msglist-new

ChatMessage

Variants
statussendingsentdeliveredreadfailed
variantbubbleplain
States
Hover (CSS)Focus inside
Dark and light
Every color comes from theme tokens, so it follows data-theme (and presets like Graphite) on the page or any wrapper. Contrast is checked in both themes.
Styling hooks
.alea-msg.alea-msg-avatar.alea-msg-main.alea-msg-head.alea-msg-author.alea-msg-time.alea-msg-body.alea-msg-bubble.alea-msg-actions.alea-msg-meta.alea-msg-status.alea-msg-thread
Data attributes
data-groupeddata-variant=bubbledata-variant=plaindata-status=readdata-status=faileddata-status=sendingdata-own

ReactionBar

Variants
sizesmmd
States
Hover (CSS)Pressed (CSS)
Dark and light
Every color comes from theme tokens, so it follows data-theme (and presets like Graphite) on the page or any wrapper. Contrast is checked in both themes.
Styling hooks
.alea-reactions.alea-reaction.alea-reaction-count.alea-reaction-add.alea-emoji-popover
Data attributes
data-size=sm

TypingIndicator

Dark and light
Every color comes from theme tokens, so it follows data-theme (and presets like Graphite) on the page or any wrapper. Contrast is checked in both themes.
Styling hooks
.alea-typing.alea-typing-dots.alea-typing-text

Accessibility

  • MessageList is a log region: screen readers announce new messages as they arrive, without moving focus.
  • The list takes focus as one stop, so keyboard users can scroll it; actions inside each message are reachable with Tab.
  • Each message is an article named by its author and time; delivery states are words, not only icons.
  • Reactions are toggle buttons that say the emoji, the count and whether you reacted.
  • Hover actions also show on keyboard focus and stay visible on touch screens.
  • The typing indicator is a polite status; its dots are decoration and stop with reduced motion.

Keyboard

KeyDoes
TabMoves into the list, then through each message's actions and reactions
Arrow keysScroll the list when it has focus
Space or EnterToggles a reaction or opens the picker

Do and don't

Do

  • Group runs from the same author so long conversations stay readable.
  • Show the New messages line when people come back to a conversation.
  • Keep hover actions to three or four: reply, react, more.

Don't

  • Don't rely on the check icons alone for delivery: the status words are there for that.
  • Don't auto-scroll when people have scrolled up to read; the list only follows new messages while they are at the bottom.
  • Don't put long forms inside a message: link to them.

In Figma

ChatMessage with Own, Grouped, Variant (Bubble, Plain) and Status; ReactionBar and TypingIndicator as separate components.

Tested with axe, keyboard and screen reader roles