Dashral Pro is on the wayGet 30% off at launch

Dashral

InboxPro

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.

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

PropTypeDefault
titleReact.ReactNode"Inbox"
conversationsInboxConversation[]sample
defaultSelectedstring | null

The conversation open at first.

"sophia"
typing{ conversation: string; name?: string } | null

Whose typing shows, by conversation id (and who, in a group).

—
onSend(conversation: string, message: { text: string; file?: File }) => Promise<InboxMessage | void> | InboxMessage | void

Sends 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 replies.

—
onOpen(conversation: string) => Promise<void> | void

A 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> | void

Pin, mute, archive, or mark as unread.

—
onDelete(conversation: string) => Promise<void> | void—

type Presence

= "online" | "away" | "offline"

type InboxMessage

PropTypeDefault
idnumber | string—
fromstring

"me", or the name of who wrote it.

—
textstring—
daystring

The day it's grouped under, e.g. "Today".

—
timestring—
file{ name: string; size: string; href?: string }—
reactionstring—
failedboolean

Yours that didn't go through.

—

type InboxConversation

PropTypeDefault
idstring—
namestring—
aboutstring

Under the name in the conversation's header.

—
groupboolean—
presencePresence—
unreadnumber—
pinnedboolean—
mutedboolean—
archivedboolean—
seenboolean

Whether they've read your last message.

—
messagesMessage[]—
repliesstring[]

The demo: what they say back, in turn, when you write (without onSend).

—