> For the complete documentation index, see [llms.txt](https://dnotifier.gitbook.io/product-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dnotifier.gitbook.io/product-docs/chat/ui-patterns.md).

# Chat UI patterns

DNotifier delivers messages and history APIs — **your app** owns the conversation UI. This page collects common patterns for threads, bubbles, media, and ephemeral signals.

***

## Thread list

Maintain a list of conversations in your backend or derive from known peer IDs:

| Field                 | Source                                           |
| --------------------- | ------------------------------------------------ |
| Peer user ID          | Your user directory                              |
| Last message preview  | Latest from history or local cache               |
| Unread count          | Your app tracks last read `timestamp` per thread |
| Avatar / display name | Your user profile service                        |

DNotifier does not provide a thread-list API — you map `userId` pairs to UI rows.

***

## Message bubbles

```
  ┌─────────────────────────────┐
  │  Thread: Chat with Bob       │
  ├─────────────────────────────┤
  │         ┌──────────────┐    │  ← incoming (peer)
  │         │ Hello!       │    │
  │         └──────────────┘    │
  │    ┌──────────────┐         │  ← outgoing (self)
  │    │ Hi there     │         │
  │    └──────────────┘         │
  ├─────────────────────────────┤
  │ [ Type a message...    ] ➤  │
  └─────────────────────────────┘
```

Align bubbles by comparing `metadata.sender` to the current user's prefixed id.

```js
const isOutgoing = msg.metadata.sender.endsWith(`:${myUserId}`);
```

***

## Message types in UI

| `data.type`       | UI treatment                |
| ----------------- | --------------------------- |
| `text`            | Text bubble                 |
| `image`           | Thumbnail + tap to expand   |
| `audio`           | Play button + duration      |
| `doc`             | File icon + download        |
| `typing`          | Subtle indicator, no bubble |
| `message-deleted` | Remove row from list        |

→ [Structured payloads](/product-docs/realtime-communication/structured-payloads.md)

***

## Optimistic send

Show the outgoing message immediately, then reconcile:

1. Append local message with `status: "sending"`
2. `await send(...)`
3. Update with `metadata.id` from any server acknowledgment or mark `status: "sent"`
4. On failure, mark `status: "failed"` with retry

***

## Typing indicators

Send ephemeral payloads with `saveHistory: false`:

```js
await notifier.send({
  senderId: myUserId,
  receiverId: peerId,
  data: { type: "typing" },
  saveHistory: false,
});
```

Debounce in the input handler — do not send on every keystroke.

***

## Scroll and load

| Pattern          | Implementation                                     |
| ---------------- | -------------------------------------------------- |
| Open thread      | `fetchChatHistory` → render → scroll to bottom     |
| New live message | Append in `onMessage` → scroll if user near bottom |
| Pull to refresh  | Refetch history and merge by `id`                  |

***

## Offline state

| State        | UI                                    |
| ------------ | ------------------------------------- |
| Connected    | Normal input enabled                  |
| Disconnected | Banner + disable send; queue optional |
| Reconnecting | Spinner on banner                     |

→ [Error handling & reconnection](/product-docs/realtime-communication/error-handling.md)

***

## Read state

DNotifier does not provide built-in read receipts. Implement with:

* `send({ type: "read", lastReadId })` with `saveHistory: false`, or
* Your backend tracking read cursor per thread

***

## Accessibility

* Label send button and message list for screen readers
* Provide alt text for image messages
* Ensure sufficient color contrast for incoming vs outgoing bubbles

***

## Related topics

* [Building 1:1 chat](/product-docs/chat/building-one-to-one-chat.md)
* [Example: Minimal chat app](/product-docs/chat/example-minimal-chat.md)
* [Chat use cases](/product-docs/platform-overview/use-cases/chat.md)
