Package Reference
Component Documentation
The chat UI is built from named component slots. Every wired slot has a package default; you only pass the components you want to replace via the components prop on ChatMain (or uiConfig.components on Chat). Import the matching *SlotProps type from the package for full TypeScript support.
Which slots are wired
| Slot | Wired in | Fallback when omitted |
|---|---|---|
| ChatLayout | ChatLayout.tsx | DefaultChatLayout |
| LoggedUserDetails | DefaultChatLayout | Package default |
| ChannelList | DefaultChatLayout | Package default |
| ChannelHeader | DefaultChatLayout | Package default |
| MessageList | DefaultChatLayout | Package default |
| MessageInput | DefaultChatLayout | Package default |
| ForwardModal | DefaultChatLayout | Package default |
| ChatPanelAlerts | DefaultChatLayout | Package default |
| ChannelListItem | ChannelListItem wrapper | DefaultChannelListItem |
| Avatar | ChatAvatar | DefaultChatAvatar |
| HeaderCallActions | HeaderCallActions | Built-in phone/video group |
| PhoneCallButton / VideoCallButton | HeaderCallActions | Built-in buttons |
| HeaderLeftSide / HeaderRightSide | ChannelHeaderView | Package default |
| ChatActionModal | ChannelHeaderView | Package default |
| MembersDrawer / AdminsDrawer / PermissionDrawer | ChannelHeaderView | Package default |
| ChannelDetailsDrawer / AttachmentsDrawer | ChannelHeaderView | Package default |
| PinnedMessagesDrawer / StarredMessagesDrawer | ChannelHeaderView | Package default |
Advanced slots (customize by replacing a parent)
| Slot | Customize by replacing |
|---|---|
| MessageItem | MessageList (render your own list of custom items) |
| MessageToolbar, MessageStatus, MessageAttachments, MessageReactions, MessageReplySnippet | MessageItem or MessageList |
| HeaderSearchOverlay | HeaderRightSide or ChannelHeader |
| ChatThemeToggle, ChatDateTimeSettings, ChatSocketStatus | Parent header/sidebar or ChannelHeader |
Full component slot reference
| Slot | Replaces | Prop type |
|---|---|---|
| ChatLayout | Entire chat shell | ChatLayoutSlotProps |
| LoggedUserDetails | Sidebar profile + new chat | LoggedUserDetailsSlotProps |
| ChannelList | Conversation list | ChannelListSlotProps |
| ChannelListItem | One conversation row | ChannelListItemSlotProps |
| ChannelHeader | Full header bar | ChannelHeaderSlotProps |
| HeaderLeftSide | Back button, name, pin/star | HeaderLeftSideSlotProps |
| HeaderRightSide | Search, menu, settings | HeaderRightSideSlotProps |
| HeaderCallActions | Phone + video button group | HeaderCallActionsSlotProps |
| PhoneCallButton | Voice call button | PhoneCallButtonSlotProps |
| VideoCallButton | Video call button | VideoCallButtonSlotProps |
| HeaderSearchOverlay | Message search dropdown | HeaderSearchOverlaySlotProps |
| MessageList | Scrollable messages area | ActiveChannelMessagesSlotProps |
| MessageItem | Single message bubble | MessageItemSlotProps |
| MessageInput | Composer | ChannelMessageBoxSlotProps |
| ChatPanelAlerts | Error/info banner | ChatPanelAlertsSlotProps |
| ChatActionModal | Clear/delete/block confirm | ChatActionModalSlotProps |
| ChannelDetailsDrawer | Channel details sheet | ChannelDetailsDrawerSlotProps |
| MembersDrawer | Group members sheet | MembersDrawerSlotProps |
| AdminsDrawer | Group admins sheet | AdminsDrawerSlotProps |
| PermissionDrawer | Permissions sheet | PermissionDrawerSlotProps |
| AttachmentsDrawer | Attachments sheet | AttachmentsDrawerSlotProps |
| PinnedMessagesDrawer | Pinned messages sheet | PinnedMessagesDrawerSlotProps |
| StarredMessagesDrawer | Starred messages sheet | StarredMessagesDrawerSlotProps |
| Avatar | Avatar everywhere | AvatarSlotProps |
| MessageToolbar | Reply/forward/edit menu | MessageToolbarSlotProps |
| MessageStatus | Sent/delivered/read ticks | MessageStatusSlotProps |
| MessageAttachments | Files/images in bubble | MessageAttachmentsSlotProps |
| MessageReactions | Emoji chips | MessageReactionsSlotProps |
| MessageReplySnippet | Quoted reply in bubble | MessageReplySnippetSlotProps |
| ChatThemeToggle | Light/dark toggle | { className?: string } |
| ChatDateTimeSettings | Date/time settings button | Record<string, never> |
| ChatSocketStatus | Connection indicator | { className?: string } |
Default component fallback behavior
Customization is opt-in per slot — you never need to register every component. Internally, every wired slot calls resolveComponent(slotName, PackageDefault): if you passed a custom component it is used; otherwise the package default renders.
| You pass | Result |
|---|---|
| No components prop at all | Full default chat UI |
| components={{ Avatar: MyAvatar }} | Custom avatar only; all other slots use defaults |
| components={{ MembersDrawer: undefined }} | Treated as not passed — default drawer renders |
| classNames={{ sidebar: '...' }} | Your classes merge on top of the package defaults |
Wrapping package defaults instead of rebuilding
Use packageDefaultComponents when you only need to restyle or wrap a default component rather than rebuild it:
import {
packageDefaultComponents,
type ChatComponents,
} from "@realtimexsco/live-chat";
function withTheme<P extends object>(
Default: React.ComponentType<P>,
className: string
): React.ComponentType<P> {
return (props) => (
<div className={className}>
<Default {...props} />
</div>
);
}
const components: ChatComponents = {
MessageItem: withTheme(packageDefaultComponents.MessageItem!, "my-message"),
ChannelListItem: withTheme(packageDefaultComponents.ChannelListItem!, "my-row"),
};Code examples for common slots
The examples below show practical replacements for the slots teams customize most often. Pass only the keys you need on components — every omitted slot keeps the package default. For wrapping defaults instead of rebuilding them, use packageDefaultComponents above.
Avatar
import type { AvatarSlotProps } from "@realtimexsco/live-chat";
const MyAvatar = ({ src, name, size = "md", isOnline, showOnline }: AvatarSlotProps) => (
<div className="relative">
<img src={src || undefined} alt={name} className={`avatar avatar--${size}`} />
{showOnline && isOnline && <span className="online-dot" />}
</div>
);MessageItem (custom bubble)
import type { MessageItemSlotProps } from "@realtimexsco/live-chat";
const MyMessageItem = ({ isSender, message, createdAt }: MessageItemSlotProps) => (
<div className={isSender ? "text-right" : "text-left"}>
<div className={isSender ? "bubble-sent" : "bubble-received"}>{message}</div>
<time className="text-xs opacity-60">{createdAt}</time>
</div>
);ChannelListItem
import type { ChannelListItemSlotProps } from "@realtimexsco/live-chat";
const MyRow = ({ channel, isActive, onSelect }: ChannelListItemSlotProps) => (
<button
type="button"
className={isActive ? "row-active" : "row"}
onClick={() => onSelect(channel)}
>
{channel.name}
{channel.unreadCount ? ` (${channel.unreadCount})` : ""}
</button>
);MessageInput (composer)
import type { ChannelMessageBoxSlotProps } from "@realtimexsco/live-chat";
const MyInput = ({ onSendMessage, replyTo, onCancelReply }: ChannelMessageBoxSlotProps) => {
const [text, setText] = useState("");
return (
<div>
{replyTo && <button type="button" onClick={onCancelReply}>Cancel reply</button>}
<input value={text} onChange={(e) => setText(e.target.value)} />
<button
type="button"
onClick={() => { onSendMessage?.(text, [], replyTo); setText(""); }}
>
Send
</button>
</div>
);
};MembersDrawer (full custom drawer)
Register it on ChatMain: components={{ MembersDrawer: MyMembersDrawer }}. Remove that key to restore the package default drawer.
import { useChatStore, type MembersDrawerSlotProps } from "@realtimexsco/live-chat";
const MyMembersDrawer = ({
isOpen,
onOpenChange,
conversationInfo,
}: MembersDrawerSlotProps) => {
const manageGroupMembers = useChatStore((s) => s.manageGroupMembers);
const participants = conversationInfo?.participants ?? [];
if (!isOpen) return null;
return (
<aside className="members-drawer">
<header>
<h2>Members ({participants.length})</h2>
<button type="button" onClick={() => onOpenChange(false)}>Close</button>
</header>
<ul>
{participants.map((p, i) => {
const id = typeof p === "string" ? p : p._id;
const name = typeof p === "string" ? "User" : p.name;
return <li key={`${id}-${i}`}>{name}</li>;
})}
</ul>
</aside>
);
};All classNames keys
Class overrides merge on top of package defaults rather than replacing components entirely:
| Key | UI region |
|---|---|
| shell | Outermost chat wrapper |
| mainPanel | Inner rounded panel |
| sidebar | Left sidebar |
| loggedUserDetails | Profile block at top |
| channelList / channelListItem | Conversation list / each row |
| channelListItemActive | Selected conversation row |
| channelHeader / headerLeft / headerRight | Header bar and its sections |
| headerCallActions / phoneCallButton / videoCallButton | Call button group and buttons |
| messageList / messageItem | Messages scroll area / row wrapper |
| messageBubble / messageBubbleSender / messageBubbleReceiver | Bubble styling, both / outgoing / incoming |
| messageInput / messageInputTextarea | Composer container / textarea |
| avatar / avatarFallback | Avatar wrapper / initials fallback |
| dateDivider | "Today" / date separator |
| emptyState | No messages placeholder |
| forwardModal | Forward dialog |
| chatPanelAlerts | Error/info alert bar |
| drawer / drawerContent | Drawer overlay/shell / panel body |
| searchOverlay | In-header search results |
classNames={{
shell: "chat-container-root",
channelListItemActive: "bg-indigo-50 dark:bg-indigo-500/10",
messageBubbleSender: "rounded-2xl shadow-sm",
messageBubbleReceiver: "rounded-2xl",
drawer: "z-[60]",
}}Events
The package does not expose a separate global event-emitter API for events — instead, event-style behavior is delivered through callback props and hook subscriptions. The table below summarizes the callback-based "events" available.
| Event (callback prop) | Fires when | Where |
|---|---|---|
| onColorModeChange | The light/dark mode changes | ChatMain |
| onDateTimePreferencesChange | The user changes locale/timezone/12-24h settings | ChatMain |
| onErrorDismiss / onInfoDismiss | The alert banner is dismissed | ChatMain |
| onPhoneCall / onVideoCall | The user taps the call button (features prop) | ChatMain |
| onMessageReceived | A new message arrives in the background | Chat (provider) |
| onSocketConnected | The socket connection is established | Chat (provider) |
| onSocketError | The socket connection errors | Chat (provider) |
| onSendMessage | The composer submits a message (slot prop) | MessageInput slot |
| onSelect | A conversation row is clicked (slot prop) | ChannelListItem slot |
| onOpenChange | A drawer or modal opens/closes (slot prop) | Drawer slots |