The UI Kit includes a full chat panel and lower-level chat components. The chat components load messages in pages, instead of loading the entire chat history when they join. This keeps chat responsive in meetings with many participants or long chat history.
Use the full panel when you want RealtimeKit to manage chat behavior for you.
Use lower-level components when you need to control the layout around message lists, pinned messages, or the composer.
Use rtk-chat to render the full chat panel. It includes public chat, private chat, paginated messages, pinned messages, file uploads, image uploads, edit actions, delete actions, and emoji input.
<rtk-ui-provider id="rtk-ui-provider">
<rtk-chat style="height: 480px;"></rtk-chat>
</rtk-ui-provider>To set chat UI overrides, assign the overrides property on rtk-ui-provider or rtk-meeting.
const provider = document.querySelector("rtk-ui-provider");
provider.overrides = {
disableEmojiPicker: true,
disablePrivateChat: true,
};The disableEmojiPicker override hides the emoji picker button. The disablePrivateChat override hides private chat even when the preset allows it.
To control private chat for all participants, prefer preset permissions.
Use RtkChat to render the full chat panel. It includes public chat, private chat, paginated messages, pinned messages, file uploads, image uploads, edit actions, delete actions, and emoji input.
import { RtkChat, RtkUiProvider } from "@cloudflare/realtimekit-react-ui";
function ChatPanel({ meeting }) {
return (
<RtkUiProvider
meeting={meeting}
overrides={{
disableEmojiPicker: true,
disablePrivateChat: true,
}}
>
<RtkChat style={{ height: "480px" }} />
</RtkUiProvider>
);
}The disableEmojiPicker override hides the emoji picker button. The disablePrivateChat override hides private chat even when the preset allows it.
To control private chat for all participants, prefer preset permissions.
Use rtk-chat to render the full chat panel. It includes public chat, private chat, paginated messages, pinned messages, file uploads, image uploads, edit actions, delete actions, and emoji input.
<rtk-ui-provider [meeting]="meeting" [overrides]="chatOverrides">
<rtk-chat style="height: 480px;"></rtk-chat>
</rtk-ui-provider>chatOverrides = {
disableEmojiPicker: true,
disablePrivateChat: true,
};The disableEmojiPicker override hides the emoji picker button. The disablePrivateChat override hides private chat even when the preset allows it.
To control private chat for all participants, prefer preset permissions.
You can create your own chat layout from the same UI Kit components that RtkChat uses. Place each component wherever your design needs it, such as the message list in a sidebar and the composer in a footer, and connect them through your own state.
| Component | What it renders |
|---|---|
RtkChatSelector |
A dropdown to switch between public chat and private conversations. Emits rtkChatSelectorChange with the selected participant. |
RtkPinnedMessageSelector |
A collapsible header that expands to show pinned messages. |
RtkChatMessagesUiPaginated |
The message list. Loads public messages when privateChatRecipient is empty, and the private conversation when you pass a participant. |
RtkChatComposerView |
The message input, with file, image, and emoji buttons. |
When you build your own layout, your code connects the components to meeting.chat:
RtkChatMessagesUiPaginatedemitspinMessage,editMessage, anddeleteMessageevents from its message menu but does not act on them. Handle these events and call the matchingmeeting.chatmethods.RtkChatComposerViewemitsnewMessageandeditMessageevents. Send or edit the message withmeeting.chat.- Pass
meeting.chat.maxTextLimitandmeeting.chat.rateLimitstoRtkChatComposerViewso the composer enforces the same limits as the meeting.
The following example stacks the components vertically. Rearrange them to fit your layout.
import {
RtkChatComposerView,
RtkChatMessagesUiPaginated,
RtkChatSelector,
RtkPinnedMessageSelector,
} from "@cloudflare/realtimekit-react-ui";
import { useState } from "react";
function CustomChat({ meeting }) {
const [privateChatRecipient, setPrivateChatRecipient] = useState(null);
const [editingMessage, setEditingMessage] = useState(null);
const { chatPublic, chatPrivate } = meeting.self.permissions;
const publicChat = {
canSendText: chatPublic.canSend && chatPublic.text,
canSendFiles: chatPublic.canSend && chatPublic.files,
};
const privateChat = {
canSendText: Boolean(chatPrivate?.canSend && chatPrivate?.text),
canSendFiles: Boolean(chatPrivate?.canSend && chatPrivate?.files),
};
const activeChat = privateChatRecipient ? privateChat : publicChat;
return (
<div style={{ height: "480px" }}>
<RtkChatSelector
meeting={meeting}
onRtkChatSelectorChange={(event) => {
setPrivateChatRecipient(event.detail.selectedUser ?? null);
}}
/>
<RtkPinnedMessageSelector meeting={meeting} />
<RtkChatMessagesUiPaginated
meeting={meeting}
privateChatRecipient={privateChatRecipient}
onPinMessage={(event) => {
const message = event.detail;
if (message.pinned) {
meeting.chat.unpin(message.id);
} else {
meeting.chat.pin(message.id);
}
}}
onEditMessage={(event) => {
if (event.detail.type === "text") {
setEditingMessage(event.detail);
}
}}
onDeleteMessage={(event) => {
if (editingMessage?.id === event.detail.id) {
setEditingMessage(null);
}
meeting.chat.deleteMessage(event.detail.id);
}}
/>
<RtkChatComposerView
canSendTextMessage={activeChat.canSendText}
canSendFiles={activeChat.canSendFiles}
maxLength={meeting.chat.maxTextLimit}
rateLimits={meeting.chat.rateLimits}
inputTextPlaceholder="Enter a message"
isEditing={!!editingMessage}
message={editingMessage ? editingMessage.message : ""}
storageKey={
editingMessage
? `custom-chat-edit-${editingMessage.id}`
: "custom-chat-draft"
}
onNewMessage={(event) =>
meeting.chat.sendMessage(
event.detail,
privateChatRecipient ? [privateChatRecipient.id] : [],
)
}
onEditMessage={async (event) => {
try {
await meeting.chat.editTextMessage(editingMessage.id, event.detail);
} finally {
setEditingMessage(null);
}
}}
onEditCancel={() => setEditingMessage(null)}
/>
</div>
);
}Refer to the RtkChat, RtkChatSelector, RtkPinnedMessageSelector, RtkChatMessagesUiPaginated, and RtkChatComposerView API references for component props.