> ## Documentation Index
> Fetch the complete documentation index at: https://api.fanvue.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# ChatMessage

> A single chat message rendered as a bubble.

```tsx theme={null}
import { ChatMessage } from "@fanvue/ui";
import type {
  ChatMessageProps,
  ChatMessageStatus,
  ChatMessageUser,
  ChatMessageVariant,
} from "@fanvue/ui";
```

## Examples

## All Variants

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatmessage--all-variants&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="320" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatMessage — All Variants" />
</Frame>

```tsx theme={null}
import { ChatMessage } from "@fanvue/ui";

const AVATAR = "https://i.pravatar.cc/80?img=47";

<div className="flex flex-col gap-3">
  <ChatMessage user="sender" variant="typing" />
  <ChatMessage user="receiver" variant="typing" avatarSrc={AVATAR} online />
  <ChatMessage
    user="receiver"
    message="Placeholder message."
    time="16:00"
    avatarSrc={AVATAR}
    online
  />
  <ChatMessage user="sender" message="Placeholder message." time="16:00" />
  <ChatMessage
    user="receiver"
    message="Placeholder message sits here, please change me."
    time="16:00"
    avatarSrc={AVATAR}
    online
  />
  <ChatMessage
    user="sender"
    message="Placeholder message sits here, please change me."
    time="16:00"
  />
  <ChatMessage
    user="receiver"
    variant="audio"
    audioDuration="0:05"
    time="16:00"
    avatarSrc={AVATAR}
    online
  />
  <ChatMessage user="sender" variant="audio" audioDuration="0:05" time="16:00" />
  <ChatMessage user="receiver" variant="deleted" time="16:00" avatarSrc={AVATAR} online />
  <ChatMessage user="sender" variant="deleted" time="16:00" />
</div>
```

## Read Receipt

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatmessage--read-receipt&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="320" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatMessage — Read Receipt" />
</Frame>

```tsx theme={null}
import { ChatMessage } from "@fanvue/ui";

<ChatMessage
  user="sender"
  message="Placeholder message."
  time="16:00"
  status="read"
/>
```

## Conversation

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-chatmessage--conversation&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="320" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="ChatMessage — Conversation" />
</Frame>

```tsx theme={null}
import { ChatMessage } from "@fanvue/ui";

const AVATAR = "https://i.pravatar.cc/80?img=47";

<div className="flex flex-col gap-2">
  <ChatMessage
    user="receiver"
    message="Hey! Are you free later?"
    time="15:58"
    avatarSrc={AVATAR}
    online
  />
  <ChatMessage user="sender" message="Yeah, after 5." time="15:59" status="read" />
  <ChatMessage
    user="sender"
    message="Want to grab something to eat around the corner?"
    time="15:59"
    status="read"
  />
  <ChatMessage user="receiver" variant="typing" avatarSrc={AVATAR} online />
  <ChatMessage
    user="receiver"
    variant="audio"
    audioDuration="0:12"
    time="16:01"
    avatarSrc={AVATAR}
    online
  />
  <ChatMessage user="receiver" variant="deleted" time="16:02" showAvatar={false} />
  <ChatMessage
    user="sender"
    message="Perfect, see you there!"
    time="16:03"
    status="delivered"
  />
</div>
```

## Props

## ChatMessage

A single chat message rendered as a bubble. Sender messages sit on the right with a green bubble and a delivery tick; receiver messages sit on the left with a grey bubble and an avatar. Supports plain text, a typing indicator, a voice message with waveform, and a deleted-message placeholder.

Text bubbles place the timestamp inline after short messages and drop it to the bottom-right corner once the text wraps, so no variant switch is needed for short versus long content.

<ParamField path="audioDuration" type="string" default="0:00">
  Duration label for the `"audio"` variant, e.g. `"0:05"`.
</ParamField>

<ParamField path="avatarAlt" type="string" default="Avatar">
  Avatar alt text.
</ParamField>

<ParamField path="avatarFallback" type="ReactNode">
  Avatar fallback (initials or icon) shown before the image loads.
</ParamField>

<ParamField path="avatarSrc" type="string">
  Avatar image URL for receiver messages.
</ParamField>

<ParamField path="defaultPlaying" type="boolean" default="false">
  Initial playing state when uncontrolled.
</ParamField>

<ParamField path="deletedLabel" type="string" default="Message deleted">
  Text shown for the `"deleted"` variant.
</ParamField>

<ParamField path="message" type="ReactNode">
  Message body for the `"text"` variant. Keep it to inline content.
</ParamField>

<ParamField path="online" type="boolean" default="false">
  Show the online indicator on the receiver avatar.
</ParamField>

<ParamField path="onPlayingChange" type="((playing: boolean) => void)">
  Fired when the audio play/pause button is pressed, with the next playing state.
</ParamField>

<ParamField path="pauseLabel" type="string" default="Pause">
  Accessible label for the audio pause button.
</ParamField>

<ParamField path="playing" type="boolean">
  Whether the audio is playing (controlled). Pairs with `onPlayingChange`.
</ParamField>

<ParamField path="playLabel" type="string" default="Play">
  Accessible label for the audio play button.
</ParamField>

<ParamField path="showAvatar" type="boolean" default="true">
  Render the receiver avatar. Reserves the avatar space when `false` so grouped bubbles stay aligned.
</ParamField>

<ParamField path="status" type="&#x22;delivered&#x22; | &#x22;read&#x22;" default="delivered">
  Delivery status shown on sender messages (a double tick). Ignored for receiver messages. `"read"` renders the tick in the read colour.
</ParamField>

<ParamField path="time" type="string">
  Timestamp shown with the message, e.g. `"16:00"`.
</ParamField>

<ParamField path="typingLabel" type="string" default="Typing">
  Accessible label for the typing indicator.
</ParamField>

<ParamField path="user" type="&#x22;sender&#x22; | &#x22;receiver&#x22;" default="receiver">
  Who sent the message. `"sender"` is the current user (right-aligned, green bubble, delivery tick). `"receiver"` is the other party (left-aligned, grey bubble, with avatar).
</ParamField>

<ParamField path="variant" type="&#x22;audio&#x22; | &#x22;text&#x22; | &#x22;typing&#x22; | &#x22;deleted&#x22;" default="text">
  The kind of content the message carries.
</ParamField>

<ParamField path="waveform" type="number[]">
  Relative bar heights (values `0`–`1`) for the `"audio"` waveform. Defaults to a flat row of dots matching the unplayed design state.
</ParamField>

## Exported types

Also exported from `@fanvue/ui`: `ChatMessageProps`, `ChatMessageStatus`, `ChatMessageUser`, `ChatMessageVariant`.

***

**Setup:** [Installation](/docs/ui/installation) · [Theming](/docs/ui/theming)
