# 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.

**Dependencies:** npm: 1 direct, 2 total; registry: 2 direct, 2 total.

## 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

```tsx
<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.

```tsx
<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

| Name | Type | Values | Default | Description |
| --- | --- | --- | --- | --- |
| `label` (required) | `string` |  |  | On ConversationList: names the navigation landmark, such as Conversations. |
| `title` (required) | `node` |  |  | On ConversationListItem: the person, group or agent, such as Linh Tran. |
| `preview` | `node` |  |  | The last message, on one line. |
| `time` | `node` |  |  | When the last message came, as shown, such as 10:42 or Mon. |
| `dateTime` | `string` |  |  | The machine-readable time, such as 2026-10-23T10:42. |
| `avatar` | `node` |  |  | An Avatar at the start, or a GroupAvatar for a group. Pass alt="" when title names the same person or group. |
| `unread` | `number \| boolean` |  |  | The number of unread messages, or true for an unread dot. 0 or false: read. |
| `typing` | `boolean \| string` |  | `false` | Someone 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. |
| `active` | `boolean` |  | `false` | The open conversation: aria-current="page" and the muted accent fill. |
| `href` | `string` |  |  | With it the row is a link; without it a button. |
| `asChild` | `boolean` |  | `false` | For 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

| Part | Description |
| --- | --- |
| `root` | The navigation landmark. |
| `list` | The ul of rows. |
| `conversation` | One row: a link or button with the avatar, then two lines. |
| `avatar` | Optional Avatar, or GroupAvatar for a group, at the start. Size lg suits two lines. |
| `title` | The person, group or agent, on one line. Semibold while unread. |
| `time` | When the last message came, at the end of the first line. |
| `preview` | The last message on one line, cut with an ellipsis. Primary text while unread. |
| `typing` | While 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. |
| `unread` | The unread count: a solid accent pill (99+ above 99), or an 8px accent dot for unread=true. |

## Accessibility

Role: `navigation`

| Keys | Action |
| --- | --- |
| `Tab` | Moves to the next conversation. |
| `Enter` | Opens 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

```bash
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](https://www.werewolf-ui.dev/docs/installation.md) for requirements and the alternative registry setup.
