Chatpack

UI Blocks

Reusable React blocks for Chatpack chat experiences.

Browse layouts, input controls, realtime status, group tools, and message primitives from @chatpack/ui. Previews use sample content. Connected components need a ChatpackUIProvider and a client in your app.

Install

pnpm add @chatpack/ui @chatpack/client

Import the stylesheet once, then provide a React-enabled client and the viewer id. User ids are opaque to Chatpack, so applications can render their own profiles:

import { createChatClient } from "@chatpack/client/react";
import { ChatpackUIProvider, ChatWindow } from "@chatpack/ui";
import "@chatpack/ui/styles.css";

const client = createChatClient({ baseURL: "/", basePath: "/api/chat" });

export function Chat({ conversationId, userId }: { conversationId: string; userId: string }) {
  return (
    <ChatpackUIProvider client={client} userId={userId} renderUser={(id) => <span>{id}</span>}>
      <ChatWindow conversationId={conversationId} />
    </ChatpackUIProvider>
  );
}

Current Blocks

Layout

ConversationList, CompactChatList, ConversationHeader, ConversationRow, MessageThread, FlatMessageThread, GroupedMessageThread, MessageRow, ChatWindow, InboxLayout, MobileChatSheet, FloatingChatWidget, AssistantThread, JumpToLatest

Input

MessageComposer, ReplyComposer, MentionComposer, MentionAutocomplete, ChatComposerBar, MessageActions, ForwardDialog, MessageSearch, MessageSearchResults, ChatCommandPalette, StartDirectMessage, NewGroupForm, QuickReactions, MessageReactions

Realtime

TypingIndicator, TypingDots, ConnectionStatus, PresenceBar, PresenceAvatarStack, PresenceIndicator, OnlineStatusChip, ReadReceipts, UnreadInbox, MarkReadButton

Groups

MembersList, ParticipantManager, InviteManager, InviteAccept, JoinRequests, ChannelDirectory, ChannelSettings, LeaveGroup

Moderation

BlockedUsers, MuteToggle, MutedList, ReportDialog, ModerationQueue, BanManager

Media

AttachmentComposer, AttachmentDropzone, MessageAttachments, ImageBubble, FileBubble, UploadProgress, AttachmentGallery, UnavailableAttachment

Primitives

UserAvatarUnreadBadge, ChatPrimitives, MessageBubble, Timestamp, PresenceDot, ReadReceiptTicks, ReactionPill, ReplyQuoteBar, ForwardedLabel, MentionChip, RoleTag, ErrorNotice, SystemMessage, SoftDeletedTombstone, EmptyInbox, EmojiPicker

All data comes from the public client hooks and actions. Realtime blocks do not implement their own reconnect or polling logic, and reactions are never copied into component state.

The gallery highlights 42 exported components. The full list above covers the package. Blocks that depend on host policy accept callbacks instead of embedding authentication or user-database assumptions.

Connected block contract

Configure one React client at module scope and pass it to ChatpackUIProvider. The provider owns only the opaque viewer id and profile renderer. It does not create users, authenticate requests, or invent profile fields.

import { createChatClient } from "@chatpack/client/react";
import { ChatpackUIProvider, ChatWindow } from "@chatpack/ui";
import "@chatpack/ui/styles.css";

const client = createChatClient({ baseURL: "/", basePath: "/api/chat" });

export function Chat({ conversationId, userId }: { conversationId: string; userId: string }) {
  return (
    <ChatpackUIProvider client={client} userId={userId} renderUser={(id) => <span>{id}</span>}>
      <ChatWindow conversationId={conversationId} />
    </ChatpackUIProvider>
  );
}

Message actions call messages.edit, messages.delete, messages.react, messages.unreact, and messages.forward. Ownership is checked before edit and delete controls render; core remains the final authorization boundary. MessageComposer sends on Enter, preserves Shift+Enter, and throttles typing signals to one start action per three seconds. Message lists reverse the client's newest-first page for display and call markRead for the newest item.

Group, channel, invite, join-request, and moderation blocks call their typed client actions. They do not accept fake report, mute, member, or channel arrays. Host callbacks remain for profile rendering, navigation, and success handling.

Filepack attachments

Media metadata contains only id, name, contentType, and size. It never contains a URL. Configure @chatpack/file in the host and pass its authorized resolveTarget implementation to ImageBubble, FileBubble, MessageAttachments, or AttachmentGallery. A missing or failed target shows the unavailable state. UI must not call Chatpack routes directly or expose long-lived storage URLs.

Public API quick reference

The blocks are small compositions around the public client. The props below are the main integration points; the TypeScript declarations remain the complete reference.

Connected layout and input blocks

BlockMain props
ConversationListselectedId?, onSelect?, className?, renderUser?
MessageThreadconversationId, onReply?, className?, showHeader?, onEmptyAction?, renderUser?
ChatWindowconversationId, className?
MessageComposerconversationId, replyTo?, disabled?, placeholder?, onSent?, onClearReply?
ConnectionStatusNo props; reads the client's realtime status
MessageActionsmessage, canEdit?, onReply?, onForward?, onComplete?
MessageSearchonSelect?
QuickReactionsmessage

ConversationList passes the selected ClientConversation to onSelect. MessageThread passes the selected ClientMessage to onReply. The composed blocks CompactChatList, FlatMessageThread, GroupedMessageThread, InboxLayout, MobileChatSheet, FloatingChatWidget, and AssistantThread wrap these connected blocks and preserve their client-backed behavior.

Realtime, groups, and moderation

BlockMain props
TypingIndicator, TypingDotsconversationId
PresenceIndicator, OnlineStatusChipuserId
PresenceBar, PresenceAvatarStackuserIds
ReadReceiptsconversationId, messageSeq
UnreadInboxconversationId, onSelect?
MarkReadButtonconversationId, messageId
ParticipantManager, JoinRequestsconversationId, renderUser?
InviteManager, ChannelSettings, MuteToggleconversationId
InviteAcceptcode, onAccepted?
ChannelDirectoryonJoined?
LeaveGroupconversationId, onLeft?
ReportDialogtargetType, targetId, onDone?
BlockedUsers, MutedListrenderUser?

These blocks use typed client actions for conversations, invites, channels, join requests, moderation, and participant changes. The host still owns authentication, profile rendering, navigation, and any success or error workflow outside the block.

Theme

Import styles.css for the package defaults. Override a subtree with ChatpackUIThemeProvider when the host needs a small token adjustment:

import { ChatpackUIThemeProvider, ChatWindow } from "@chatpack/ui";

<ChatpackUIThemeProvider theme={{ accent: "#2563eb", accentContrast: "#ffffff", radius: "1rem" }}>
  <ChatWindow conversationId={conversationId} />
</ChatpackUIThemeProvider>;

Theme keys include surface, panel, sidebar, border, input, text, muted, mutedSurface, accent, accentContrast, highlight, highlightContrast, secondary, secondaryContrast, bubbleOwn, bubbleOwnMuted, bubbleOwnContrast, bubbleOther, destructive, online, mentionRing, controlShadow, panelShadow, dialogShadow, subtleShadow, and radius.

Replies and threads

MessageComposer.replyTo and ReplyQuoteBar describe a reply to one message. They do not replace a full threaded-replies surface. A threaded UI still needs root-message identity, thread pagination, unread state, and navigation. Use the client thread APIs and app-owned routing or panels for those surfaces until a dedicated thread block is exported.