Conversations beside the open one: search, unread and archived, pin or mute; write with an emoji or a file and see when it's read.
When to use
- Conversations beside the open one: search, unread and archived, pin, mute, reactions and files.
- Support inboxes, marketplaces' buyer–seller messages and in-app chat.
When not to use
- Notifications that ask for an action rather than a reply: Notifications.
- Support conversations with assignment, SLAs and macros: a help desk tool does more than a chat.
Usage
Inbox with your own data: every prop has the sample as its default, so pass only what you have.
import { Inbox } from "@/components/dashral/blocks/inbox"
<Inbox
conversations={conversations}
typing={typingIn}
onSend={(conversation, message) => api.messages.send(conversation, message)}
onOpen={(id) => api.conversations.read(id)}
onReact={(conversation, message, emoji) => api.messages.react(conversation, message, emoji)}
/>API reference
Inbox
An inbox: conversations on one side — search, All / Unread / Archived, pinned first, unread counts — and the conversation on the other, with messages grouped by day and by sender, reactions, files and read receipts. Write with Enter (Shift+Enter for a new line), add an emoji or a file; they read it and type back. Pin, mute, mark as unread, archive or delete a conversation. On phones, the list and the conversation take turns. Your conversations come in as conversations (a new list replaces what's shown, e.g. as messages arrive), and every change goes to your handlers; a send that fails says so under the message, and anything else that throws is undone.
| Prop | Type | Default |
|---|---|---|
title | React.ReactNode | "Inbox" |
conversations | InboxConversation[] | sample |
defaultSelected | string | nullThe conversation open at first. | "sophia" |
typing | { conversation: string; name?: string } | nullWhose typing shows, by conversation id (and who, in a group). | — |
onSend | (conversation: string, message: { text: string; file?: File }) => Promise<InboxMessage | void> | InboxMessage | voidSends your message, with the file picked if any. Resolve with the message as stored to show it so; throw and it's marked not sent. Without it, they answer from | — |
onOpen | (conversation: string) => Promise<void> | voidA conversation was opened (and so read). | — |
onReact | (conversation: string, message: InboxMessage["id"], emoji: string | null) => Promise<void> | void | — |
onUpdate | (conversation: string, update: Partial<Pick<InboxConversation, "pinned" | "muted" | "archived" | "unread">>) => Promise<void> | voidPin, mute, archive, or mark as unread. | — |
onDelete | (conversation: string) => Promise<void> | void | — |
type Presence
= "online" | "away" | "offline"type InboxMessage
| Prop | Type | Default |
|---|---|---|
id | number | string | — |
from | string"me", or the name of who wrote it. | — |
text | string | — |
day | stringThe day it's grouped under, e.g. "Today". | — |
time | string | — |
file | { name: string; size: string; href?: string } | — |
reaction | string | — |
failed | booleanYours that didn't go through. | — |
type InboxConversation
| Prop | Type | Default |
|---|---|---|
id | string | — |
name | string | — |
about | stringUnder the name in the conversation's header. | — |
group | boolean | — |
presence | Presence | — |
unread | number | — |
pinned | boolean | — |
muted | boolean | — |
archived | boolean | — |
seen | booleanWhether they've read your last message. | — |
messages | Message[] | — |
replies | string[]The demo: what they say back, in turn, when you write (without onSend). | — |