Skip to content

Build Your Own UI

This guide explains how to use RealtimeKit UI Kit components to build a custom meeting interface instead of the default full-screen meeting view.

Prerequisites

This page builds upon the Initialize SDK, Render Default Meeting UI, and UI Kit States guides. First refer to these pages to understand the core concepts.

The code examples on this page assume you have already imported the necessary packages and initialized the SDK.

Build a custom UI with UI Kit

If the default meeting component does not provide enough control over layout or behavior, use UI Kit components to build a custom interface. The UI Kit provides pre-built components on top of the Core SDK. You can mix and match pieces while saving time compared to building from scratch.

A custom UI requires you to manage participant audio, notifications, dialogs, component layout, and screen transitions.

Similar to RtkMeeting, RtkUiProvider, another UI Kit component that acts as a provider, also listens to states and syncs them with the UI Kit components.

Unlike RtkMeeting, RtkUiProvider allows you to pass any child components to it. If any child component is a RealtimeKit component starting with Rtk, RtkUiProvider will coordinate with it to sync the states.

Example code

import {
RealtimeKitProvider,
useRealtimeKitClient,
} from "@cloudflare/realtimekit-react";
import {
RtkUiProvider,
RtkHeader,
RtkStage,
RtkGrid,
RtkSidebar,
RtkControlbar,
RtkNotifications,
RtkParticipantsAudio,
RtkDialogManager,
RtkSetupScreen,
RtkWaitingScreen,
RtkEndedScreen,
States,
} from "@cloudflare/realtimekit-react-ui";
import { useEffect, useState } from "react";
function MeetingContainer() {
const [meeting, initMeeting] = useRealtimeKitClient();
const [currentState, setCurrentState] = useState("idle");
const [showSidebar, setShowSidebar] = useState(false);
useEffect(() => {
initMeeting({
authToken: "participant_auth_token",
});
}, []);
const renderSetupScreen = () => {
return <RtkSetupScreen />;
};
const renderWaitingScreen = () => {
return <RtkWaitingScreen />;
};
const renderJoinedScreen = () => {
return (
<>
<RtkHeader
style={{ display: "flex", justifyContent: "space-between" }}
/>
<RtkStage style={{ flex: 1, flexGrow: 1, flexShrink: 1 }}>
<RtkGrid />
<RtkSidebar
style={{
position: "fixed",
top: "0px",
display: showSidebar ? "block" : "none",
}}
/>
</RtkStage>
<RtkControlbar
style={{ display: "flex", justifyContent: "space-between" }}
/>
</>
);
};
const renderEndedScreen = () => {
return <RtkEndedScreen />;
};
// Listen for state updates from RtkUiProvider
const handleStatesUpdate = (event: { detail: States }) => {
const meetingState = event.detail.meeting;
const states = event.detail;
// Store states to update your custom UI
if (meetingState === "idle" && currentState !== "idle") {
setCurrentState("idle");
} else if (meetingState === "setup" && currentState !== "setup") {
setCurrentState("setup");
} else if (meetingState === "waiting" && currentState !== "waiting") {
setCurrentState("waiting");
} else if (meetingState === "joined" && currentState !== "joined") {
setCurrentState("joined");
} else if (meetingState === "ended" && currentState !== "ended") {
setCurrentState("ended");
}
// Update sidebar visibility based on state
if (states.activeSidebar !== undefined) {
setShowSidebar(states.activeSidebar);
}
};
return (
<RealtimeKitProvider value={meeting}>
<RtkUiProvider
meeting={meeting}
showSetupScreen={true}
onRtkStatesUpdate={handleStatesUpdate}
style={{
display: "flex",
flexDirection: "column",
height: "100vh",
margin: 0,
}}
>
<div
id="meeting-container"
style={{
display: "flex",
flexDirection: "column",
flex: 1,
flexGrow: 1,
flexShrink: 1,
}}
>
{currentState === "idle" && <div>Meeting is loading...</div>}
{currentState === "setup" && renderSetupScreen()}
{currentState === "waiting" && renderWaitingScreen()}
{currentState === "joined" && renderJoinedScreen()}
{currentState === "ended" && renderEndedScreen()}
</div>
<RtkParticipantsAudio />
<RtkDialogManager />
<RtkNotifications />
</RtkUiProvider>
</RealtimeKitProvider>
);
}
function App() {
return <MeetingContainer />;
}

First level split of RtkMeeting using RtkUiProvider has the following components:

RtkHeader is the header component that shows the session name and the session controls.
RtkStage is the container component that contains the grid and sidebar components.
RtkGrid is the grid component that shows the participants in the session.
RtkSidebar is the sidebar component that shows the sidebar, in which chat, polls content shows up.
RtkControlbar is the controlbar component that shows the controls, such as camera, microphone, etc.
RtkNotifications is the notifications component that shows the notifications for the session.
RtkParticipantsAudio is the audio component that helps you listen other participants in the session.
RtkDialogManager is the dialog-manager component that shows the dialogs for the session.

You can split all of these components further. To see more such components, please refer to our components library.

We have our UI Kit open source on GitHub, you can find it here.