Skip to content

Pro pre-sale is open. Installation opens January 2027. See Pro

Components

ConversationList

A named list of conversations, such as the column beside a chat: each row links to one, with an avatar, the name, the time and the last message, and a count of unread messages. The open conversation takes the muted accent fill.

  • npm: 1 direct, 2 total
  • registry: 2 direct, 2 total

Preview

import { Avatar } from "@/components/ui/avatar"
import { ConversationList, ConversationListItem } from "@/components/ui/conversation-list"
import { GroupAvatar } from "@/components/ui/group-avatar"

const designTeam = [{ name: "Linh Tran" }, { name: "An Pham" }, { name: "Minh Le" }, { name: "Bao Do" }]

<ConversationList label="Conversations" className="w-80 max-w-full">
  <ConversationListItem active href="#linh" title="Linh Tran" preview="Got it, thanks!" time="10:44" avatar={<Avatar alt="" color="blue" size="lg">LT</Avatar>} />
  <ConversationListItem href="#design" title="Design team" preview="Minh: The new icons are in." time="09:12" unread={3} avatar={<GroupAvatar alt="" size="lg" members={designTeam} />} />
  <ConversationListItem href="#an" title="An Pham" preview="See you Monday." time="Mon" avatar={<Avatar alt="" color="green" size="lg">AP</Avatar>} />
</ConversationList>

Usage

When to use

  • List the conversations beside a chat, with the last message, the time and unread counts.
  • Switch between past chats with an assistant.

When not to use

  • The main navigation of an app. Use Sidebar.
  • A list of people to pick from. Use Combobox.
  • Rows of data with columns. Use Table.

Examples

Inbox

import { Avatar } from "@/components/ui/avatar"
import { ConversationList, ConversationListItem } from "@/components/ui/conversation-list"
import { GroupAvatar } from "@/components/ui/group-avatar"

const designTeam = [{ name: "Linh Tran" }, { name: "An Pham" }, { name: "Minh Le" }, { name: "Bao Do" }]

<ConversationList label="Conversations" className="w-80 max-w-full">
  <ConversationListItem active href="#linh" title="Linh Tran" preview="Got it, thanks!" time="10:44" avatar={<Avatar alt="" color="blue" size="lg">LT</Avatar>} />
  <ConversationListItem href="#design" title="Design team" preview="Minh: The new icons are in." typing="Minh is typing" time="09:12" unread={3} avatar={<GroupAvatar alt="" size="lg" members={designTeam} />} />
  <ConversationListItem href="#an" title="An Pham" preview="See you Monday." time="Mon" avatar={<Avatar alt="" color="green" size="lg">AP</Avatar>} />
</ConversationList>

Without avatars

Rows without avatars suit a list of threads or assistant chats. unread as true shows a dot.

import { ConversationList, ConversationListItem } from "@/components/ui/conversation-list"

<ConversationList label="Chats" className="w-72 max-w-full">
  <ConversationListItem active title="Quarterly report summary" preview="Sales grew in two of three regions." time="Today" />
  <ConversationListItem unread title="Onboarding email draft" preview="Here is a shorter version." time="Yesterday" />
  <ConversationListItem title="SQL for churn by plan" preview="The query groups accounts by plan." time="Oct 20" />
</ConversationList>

Do and don't

Do

  • Keep the list in its own column beside the MessageList, or in a Sheet on a phone.
  • Show the last message and its time, so the reader can pick a conversation without opening it.
  • Mark the open conversation with active.

Don't

  • Do not use for site or app navigation; use Sidebar.
  • Do not show a count of 0; leave unread out once the messages are read.
  • Do not put buttons inside a row; the whole row is one link.

Props

NameTypeValuesDefaultDescription
label requiredstring--On ConversationList: names the navigation landmark, such as Conversations.
title requirednode--On ConversationListItem: the person, group or agent, such as Linh Tran.
previewnode--The last message, on one line.
timenode--When the last message came, as shown, such as 10:42 or Mon.
dateTimestring--The machine-readable time, such as 2026-10-23T10:42.
avatarnode--An Avatar at the start, or a GroupAvatar for a group. Pass alt="" when title names the same person or group.
unreadnumber | boolean--The number of unread messages, or true for an unread dot. 0 or false: read.
typingboolean | string-falseSomeone is typing in this conversation: the last message gives way to pulsing dots and the words, in secondary text. A string replaces the words, such as Linh is typing.
activeboolean-falseThe open conversation: aria-current="page" and the muted accent fill.
hrefstring--With it the row is a link; without it a button.
asChildboolean-falseFor router links: the row's classes and content move onto its only child.
labels{ unread?: (count: number | undefined) => string; typing?: string }--On ConversationList: the words read after an unread row (count is undefined for a dot) and shown while someone types. Defaults: 3 unread messages, Unread, Typing. Vietnamese: 3 tin chưa đọc, Chưa đọc, Đang soạn tin.

Anatomy

PartDescription
rootThe navigation landmark.
listThe ul of rows.
conversationOne row: a link or button with the avatar, then two lines.
avatarOptional Avatar, or GroupAvatar for a group, at the start. Size lg suits two lines.
titleThe person, group or agent, on one line. Semibold while unread.
timeWhen the last message came, at the end of the first line.
previewThe last message on one line, cut with an ellipsis. Primary text while unread.
typingWhile someone types, in place of the last message: three 4px dots that pulse one after the other on duration-loop (still under reduced motion) and the words, in secondary text.
unreadThe unread count: a solid accent pill (99+ above 99), or an 8px accent dot for unread=true.

Accessibility

Role: navigation

KeysAction
TabMoves to the next conversation.
EnterOpens the focused conversation.
  • A navigation landmark named by label (EN `Conversations`, VI `Cuộc trò chuyện`), with the rows in a list.
  • Each row is one link (or a button without href), so its name is everything it shows: name, time and last message.
  • The open conversation has aria-current="page".
  • The unread count and dot are hidden from screen readers; the row ends with words from labels.unread (EN `3 unread messages`, `Unread`). An unread row is also told apart by weight and text color, not by the accent pill alone.
  • Pass alt="" to the Avatar when title names the same person.
  • While someone types, the row's name ends with the typing words instead of the last message; the dots are hidden from screen readers.

Install

npx werewolf-ui add conversation-list

Run npx werewolf-ui init once in your app before adding components. Init sets up tokens, their CSS import and agent rules. Add installs this component and its dependencies while preserving your theme. See Installation for requirements and the alternative registry setup.