---
title: "Chat"
description: "A message list and message row for AI chat transcripts."
category: AiChat
status: beta
since: 0.3.4
tags: [chat, ai, markdown]
syncStatus: reviewed
verified: true
---

## Usage

### Basic
:::TuffDemoWrapper{demo="ChatChatListDemo" code-lang="vue"}
---
code: |
  <script setup lang="ts">
  import type { ChatMessageModel } from '@talex-touch/tuffex/chat'
  import { ref } from 'vue'

  const messages = ref<ChatMessageModel[]>([
    { id: 'system-1', role: 'system', content: 'Markdown is enabled.', createdAt: 1_705_000_000_000 },
    {
      id: 'user-1',
      role: 'user',
      content: 'Review this release cover.',
      attachments: [{ type: 'image', url: '/cover.svg', name: 'cover.svg' }],
    },
    { id: 'assistant-1', role: 'assistant', content: 'Looks ready.\n\n```ts\nconst status = "ready"\n```' },
  ])
  </script>

  <template>
    <TxChatList :messages="messages" @image-click="openPreview" />
  </template>
---
:::

### Best Practices

- Use stable ids from the conversation store for `id`, never array indexes.
- Normalize image URLs at the data boundary; the component doesn't validate or rewrite attachment sources.
- Turn off `stagger` for virtualized lists or when streaming reorders messages.
- Handle `imageClick` in the host; there is no built-in preview.
- To customize a row, render `TxChatMessage` and its slots directly.

## API Reference

### TxChatList

#### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `messages` | `ChatMessageModel[]` | required | Messages, rendered in array order. |
| `markdown` | `boolean` | `true` | Renders bodies with `TxMarkdownView`; off renders plain text. |
| `stagger` | `boolean` | `true` | Animates rows in with `TxStagger`. |
| `attachmentLabel` | `string` | - | Forwarded to each message: names image thumbnails that lack `name`. |

#### Events

| Event | Params | Description |
|------|--------|-------------|
| `imageClick` | `{ url: string, name?: string, messageId: string }` | Forwards `imageClick` from `TxChatMessage`. |

### TxChatMessage

#### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `message` | `ChatMessageModel` | required | The message to render. |
| `markdown` | `boolean` | `true` | Renders the body as Markdown or plain text. |
| `attachmentLabel` | `string` | `'Open image attachment'` | Accessible name of an image thumbnail without a `name`. |

#### Events

| Event | Params | Description |
|------|--------|-------------|
| `imageClick` | `{ url: string, name?: string, messageId: string }` | Fires when an image thumbnail is clicked. |

#### Slots

| Slot | Props | Description |
|------|------|-------------|
| `avatar` | `{ message: ChatMessageModel }` | Replaces the avatar. |
| `header` | `{ message: ChatMessageModel }` | Replaces the timestamp header. |
| `content` | `{ message: ChatMessageModel }` | Replaces the body rendering. |

### Types

#### ChatMessageModel

| Field | Type | Default | Description |
|------|------|---------|-------------|
| `id` | `string` | required | Stable message key. |
| `role` | `'user' \| 'assistant' \| 'system'` | required | Message role; sets the row alignment. |
| `content` | `string` | required | Markdown or plain-text body. |
| `createdAt` | `number` | - | Epoch timestamp, rendered as `HH:mm` after mount. |
| `avatarUrl` | `string` | - | Avatar image URL. |
| `attachments` | `ChatMessageAttachment[]` | - | Image attachments, rendered as thumbnails. |

#### ChatMessageAttachment

| Field | Type | Default | Description |
|------|------|---------|-------------|
| `type` | `'image'` | required | Attachment kind; only images today. |
| `url` | `string` | required | Thumbnail URL, also sent with `imageClick`. |
| `name` | `string` | - | Accessible name of the thumbnail button, also sent with `imageClick`. |

## Overview

- `TxChatList` renders a `TxChatMessage` per item in `messages` order, keyed by `id`.
- Image attachments are native `<button type="button">` thumbnails with lazy-loaded images; the button carries the accessible name and the `<img>` is decorative.
- `createdAt` is formatted only after mount, so SSR and client output match.

## Technologies

- Source: `packages/tuffex/packages/components/src/chat/` (`TxChatList.vue`, `TxChatMessage.vue`, `types.ts`).

<TuffDocSourceLink />

## Related components

- [ChatComposer](./chat-composer.en.mdc): text entry, attachments, and sending.
- [TypingIndicator](./typing-indicator.en.mdc): the assistant's pending state.
- [AI Elements](./ai-elements.en.mdc): prefer it when you need `tool` messages or streaming states.
