EXEPERTAI LAB

Research alpha

Time Machine
EXEPERTAI LAB
GALLERY / COLLECTION
← Browse Astryx gallery
Chat·component·@astryxdesign/core

Chat Message List

Presentational message container with density context and infinite scroll support. Provides role="log" with aria-live="polite" for accessibility. A flex spacer pushes messages to the bottom when the list isn't full; set align="top" to start messages at the top instead.

Open in Playground @astryxdesign/core/Chat

Showcases and examples

3 documented examples

Chat Message List

Basic AI chat conversation with user and assistant messages. The simplest way to render a message list with alternating sender bubbles, metadata, and a date divider.

Preview loads on approachPreview loads on approach
Exact source · chat-message-list-showcase
// Copyright (c) Meta Platforms, Inc. and affiliates.

'use client';

import {
  ChatMessageList,
  ChatMessage,
  ChatMessageBubble,
  ChatMessageMetadata,
  ChatSystemMessage,
} from '@astryxdesign/core/Chat';
import {VStack} from '@astryxdesign/core/Layout';
import {Timestamp} from '@astryxdesign/core/Timestamp';

export default function ChatMessageListShowcase() {
  return (
    <VStack style={{maxWidth: 600, height: '100%'}}>
      <ChatMessageList density="balanced">
        <ChatSystemMessage variant="divider">March 15, 2026</ChatSystemMessage>

        <ChatMessage sender="user">
          <ChatMessageBubble
            metadata={
              <ChatMessageMetadata
                timestamp={
                  <Timestamp value="2026-03-15T14:30:00" format="time" />
                }
                status="read"
              />
            }>
            How should I structure a monorepo?
          </ChatMessageBubble>
        </ChatMessage>

        <ChatMessage sender="assistant">
          <ChatMessageBubble
            metadata={
              <ChatMessageMetadata
                timestamp={
                  <Timestamp value="2026-03-15T14:30:15" format="time" />
                }
              />
            }>
            Use workspaces with a shared packages directory. Keep each package
            focused on a single concern.
          </ChatMessageBubble>
        </ChatMessage>

        <ChatMessage sender="user">
          <ChatMessageBubble
            metadata={
              <ChatMessageMetadata
                timestamp={
                  <Timestamp value="2026-03-15T14:31:00" format="time" />
                }
                status="delivered"
              />
            }>
            Should I use Yarn or pnpm for that?
          </ChatMessageBubble>
        </ChatMessage>
      </ChatMessageList>
    </VStack>
  );
}

Usage

Presentational message container with density context and infinite scroll support. Provides role="log" with aria-live="polite" for accessibility. A flex spacer pushes messages to the bottom when the list isn't full; set align="top" to start messages at the top instead.

Typed props

PropType and behavior
childrenReactNode · required
Message elements: typically ChatMessage or ChatSystemMessage.
emptyStateReactNode
Content shown when the list has no messages.
scrollToTopAction() => Promise<void>
Async action fired when user scrolls to top. Use for loading older messages. Wrapped in useTransition: shows a spinner at the top while pending.
density'compact' | 'balanced' | 'spacious' · default 'balanced'
Visual density: flows to child messages via context.
gap0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10
Gap between top-level message rows. Defaults to the selected density; override for LLM event streams or independent rows that need different spacing from density.
align'top' | 'bottom' · default 'bottom'
Vertical alignment when the list is shorter than its container. 'bottom' fills free space with a spacer so short conversations sit above the composer; 'top' omits the spacer so messages start at the top. Only affects a non-full list; overflowing lists scroll identically, preserving auto-scroll-to-bottom.
isStreamingboolean · default false
Whether an assistant message is actively streaming. Marks the log aria-busy so screen readers wait and announce the completed message once instead of re-announcing partial text on every token.