Skip to main content

ConversationList

Stacks chat messages in a scroller that follows new arrivals.

import { ConversationList } from "@/fragments/ui";Source

Preview

<ConversationList>
  <Message role="user">
    <Message.Content>Hello!</Message.Content>
  </Message>
  <Message role="assistant">
    <Message.Content>Hi there! How can I help you today?</Message.Content>

Installation

npx @usefragments/cli add conversationlist

Writes src/fragments/ui/components/ConversationList plus what it imports, the globals stylesheet, and .fragments/registry-lock.json, then prints the packages to add. No account, no key.

Your own registry: publish from Fragments Cloud and add --registry org/name. Connect a workspace.

Anatomy

ConversationList is a compound: import the root and reach its parts through dot notation.

  • ConversationList.DateSeparator
  • ConversationList.TypingIndicator

Examples

With Date Separators

A labelled rule marks where one day ends.

<ConversationList>
  <ConversationList.DateSeparator date={new Date(Date.now() - 86400000)} />
  <Message role="user">
    <Message.Content>A message from yesterday</Message.Content>
  </Message>
  <ConversationList.DateSeparator date={new Date()} />

Without Avatars

Turns sit flush when nothing needs an avatar gutter.

<ConversationList showAvatars={false}>
  <Message role="user">
    <Message.Content>Hello!</Message.Content>
  </Message>
  <Message role="assistant">
    <Message.Content>How can I help?</Message.Content>

With Typing Indicator

Animated dots hold the reply's place before it lands.

<ConversationList>
  <Message role="user">
    <Message.Content>What is TypeScript?</Message.Content>
  </Message>
  <ConversationList.TypingIndicator name="Assistant" />
</ConversationList>

Loading History

A spinner pins to the top while older turns load.

<ConversationList loadingHistory>
  <Message role="user">
    <Message.Content>This is the latest message</Message.Content>
  </Message>
</ConversationList>

Empty

A fresh conversation shows its placeholder instead of blank space.

<ConversationList
  emptyState={
    <EmptyState>
      <EmptyState.Title>No messages yet</EmptyState.Title>
      <EmptyState.Description>
        Ask a question to get started.

API

Component props
Prop
Type
Default
Description
childrenRequirednodeNot setMessage components
showAvatarsbooleantrueShow avatars for messages and typing indicators in this conversation
autoScrollunionsmartAuto-scroll behavior: true (always), false (never), or "smart" (only when near bottom)
onScrollTopfunctionNot setCallback when user scrolls to top (for loading history). Receives the scroll event.
loadingHistorybooleanfalseShow loading spinner at top when loading history
emptyStatenodeNot setContent to show when conversation is empty
scrollTopThresholdnumber50Pixels from top to trigger onScrollTop
scrollBottomThresholdnumber100Pixels from bottom for smart auto-scroll

Accessibility

  • Uses proper ARIA roles for separators
  • Typing indicator uses a status role with an aria-label
  • Smooth scroll respects reduced motion preferences
  • Keyboard navigation works within scrollable container

Guidance

Use when

  • Chat interfaces holding many messages
  • Transcripts that should follow new arrivals
  • Paging back through older message history
  • Runs of messages grouped day by day

Avoid when

  • Plain item lists with no chat context (use List)
  • A single message (use Message directly)
  • Layouts that never scroll
  • MessagechildConversationList contains Message components
  • ThinkingIndicatorchildShow ThinkingIndicator at bottom while awaiting response
  • PromptsiblingTypically paired with Prompt for input

Next steps