UI Kit Addons
Last updated Oct 19, 2026 A collection of UI Kit addons that extend RealtimeKit's prebuilt UI Kit capabilities with additional interactive components and controls for enhanced meeting experiences.
This page is not available for the iOS, Android, React Nativeplatform.
WebMobile
ReactWeb ComponentsAngular
Note
UI Kit Addons are only available for web platforms (React, Web Components, and Angular). Mobile platform support is not available.
The UI Kit addons library provides the following categories of components:
Host Controls
Host controls allow meeting hosts to manage participant permissions:
- Camera Host Control - Control participant camera permissions
- Mic Host Control - Control participant microphone permissions
- Chat Host Control - Control participant chat permissions
Reactions
Interactive engagement features for participants:
- Hand Raise - Allow participants to raise their hand to signal they want to speak
- Reactions Manager - Display emoji reactions during meetings
Participant Tile
Customize the participant tile interface:
- Participant Tile Menu - Add custom menu options to participant tiles
Participant Tab Actions
Add custom actions to the participants tab:
- Participant Menu Item - Add custom menu items to participant actions
- Participants Tab Action - Add custom action buttons to the participants tab
- Participants Tab Toggle - Add custom toggle controls to the participants tab
Video Background
Apply visual effects to participant video:
- Video Background - Apply blur or virtual backgrounds to video streams
Control Bar
Customize the meeting control bar:
- Custom Control Bar Button - Add custom buttons to the control bar
Installation
npmyarnpnpmbun
npm i @cloudflare/realtimekit-ui-addons
yarn add @cloudflare/realtimekit-ui-addons
pnpm add @cloudflare/realtimekit-ui-addons
bun add @cloudflare/realtimekit-ui-addons
npmyarnpnpmbun
npm i @cloudflare/realtimekit-ui-addons
yarn add @cloudflare/realtimekit-ui-addons
pnpm add @cloudflare/realtimekit-ui-addons
bun add @cloudflare/realtimekit-ui-addons
npmyarnpnpmbun
npm i @cloudflare/realtimekit-ui-addons
yarn add @cloudflare/realtimekit-ui-addons
pnpm add @cloudflare/realtimekit-ui-addons
bun add @cloudflare/realtimekit-ui-addons
Usage
import { useState, useEffect } from "react";
import {
RealtimeKitProvider,
useRealtimeKitClient,
} from "@cloudflare/realtimekit-react";
import { RtkMeeting } from "@cloudflare/realtimekit-react-ui";
import { registerAddons, defaultConfig } from "@cloudflare/realtimekit-ui";
// Import addons
import CameraHostControl from "@cloudflare/realtimekit-ui-addons/camera-host-control";
import MicHostControl from "@cloudflare/realtimekit-ui-addons/mic-host-control";
import ChatHostControl from "@cloudflare/realtimekit-ui-addons/chat-host-control";
import HandRaise from "@cloudflare/realtimekit-ui-addons/hand-raise";
import ReactionsManagerAddon from "@cloudflare/realtimekit-ui-addons/reactions-manager";
import ParticipantTileMenu from "@cloudflare/realtimekit-ui-addons/participant-tile-menu";
import ParticipantMenuItem from "@cloudflare/realtimekit-ui-addons/participant-menu-item";
import ParticipantsTabAction from "@cloudflare/realtimekit-ui-addons/participants-tab-action";
import ParticipantsTabToggle from "@cloudflare/realtimekit-ui-addons/participants-tab-toggle";
import RealtimeKitVideoBackground from "@cloudflare/realtimekit-ui-addons/video-background";
import CustomControlbarButton from "@cloudflare/realtimekit-ui-addons/custom-controlbar-button";
function App() {
const [meeting, initMeeting] = useRealtimeKitClient();
const [authToken, setAuthToken] = useState("<participant_auth_token>");
const [config, setConfig] = useState(defaultConfig);
useEffect(() => {
if (authToken) {
initMeeting({
authToken: authToken,
});
}
}, [authToken]);
useEffect(() => {
const initializeAddons = async () => {
if (!meeting) return;
// Initialize addons
const cameraHostControl = await CameraHostControl.init({
meeting,
hostPresets: ["webinar_presenter"],
targetPresets: ["webinar_viewer"],
addActionInParticipantMenu: true,
});
const micHostControl = await MicHostControl.init({
meeting,
hostPresets: ["webinar_presenter"],
targetPresets: ["webinar_viewer"],
addActionInParticipantMenu: true,
});
const chatHostControl = await ChatHostControl.init({
meeting,
hostPresets: ["webinar_presenter"],
targetPresets: ["webinar_viewer"],
addActionInParticipantMenu: true,
});
const handRaise = await HandRaise.init({
meeting,
canRaiseHand: true,
canManageRaisedHand: true,
handRaiseIcon:
'<svg fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M4 12.02c0 1.06.2 2.1.6 3.08l.6 1.42c.22.55.64 1.01 1.17 1.29.27.14.56.21.86.21h2.55c.77 0 1.49-.41 1.87-1.08.5-.87 1.02-1.7 1.72-2.43l1.32-1.39c.44-.46.97-.84 1.49-1.23l.59-.45a.6.6 0 0 0 .23-.47c0-.75-.54-1.57-1.22-1.79a3.34 3.34 0 0 0-2.78.29V4.5a1.5 1.5 0 0 0-2.05-1.4 1.5 1.5 0 0 0-2.9 0A1.5 1.5 0 0 0 6 4.5v.09A1.5 1.5 0 0 0 4 6v6.02ZM8 4.5v4a.5.5 0 0 0 1 0v-5a.5.5 0 0 1 1 0v5a.5.5 0 0 0 1 0v-4a.5.5 0 0 1 1 0v6a.5.5 0 0 0 .85.37h.01c.22-.22.44-.44.72-.58.7-.35 2.22-.57 2.4.5l-.53.4c-.52.4-1.04.78-1.48 1.24l-1.33 1.38c-.75.79-1.31 1.7-1.85 2.63-.21.36-.6.58-1.01.58H7.23a.87.87 0 0 1-.4-.1 1.55 1.55 0 0 1-.71-.78l-.59-1.42a7.09 7.09 0 0 1-.53-2.7V6a.5.5 0 0 1 1 0v3.5a.5.5 0 0 0 1 0v-5a.5.5 0 0 1 1 0Z" fill="#ff0000"></path></svg>',
});
const CUSTOM_REACTIONS = [
{ emoji: "🔥", label: "fire" },
{ emoji: "😢", label: "sad" },
{ emoji: "👍", label: "thumbs up" },
{ emoji: "👎", label: "thumbs down" },
{ emoji: "❤️", label: "heart" },
{ emoji: "😂", label: "laugh" },
{ emoji: "👏", label: "clap" },
{ emoji: "🎉", label: "celebrate" },
];
const reactionsAddon = await ReactionsManagerAddon.init({
meeting,
reactions: CUSTOM_REACTIONS,
canSendReactions: true,
});
const participantTileMenu = new ParticipantTileMenu(
[
{
label: "Custom Toggle",
onClick: (participantId) => {
console.log("Clicked on custom toggle for ", participantId);
},
},
],
"top-right",
);
const rightTickSVG =
"<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'><path d='M4 12l6 6 10-14' fill='none' stroke='currentColor' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/></svg>";
const participantMenuItem = new ParticipantMenuItem({
label: "Custom Menu Item",
icon: rightTickSVG,
styles: "rtk-icon { color: green !important; }",
onClick: () => {
alert("Participant Menu Item clicked");
},
});
const participantsTabAction = new ParticipantsTabAction({
onClick: () => {
alert("Clicked!");
},
label: "Click me",
position: "start",
});
const participantsTabToggle = new ParticipantsTabToggle({
onEnabled: () => {
alert("toggled true!");
},
onDisabled: () => {
alert("toggled false!");
},
label: "Click me",
initialValue: () => true,
position: "start",
});
const videoBackground = await RealtimeKitVideoBackground.init({
modes: ["blur", "virtual", "random"],
blurStrength: 30,
meeting,
images: [
"https://images.unsplash.com/photo-1487088678257-3a541e6e3922?q=80&w=2874&auto=format&fit=crop&ixlib=rb-4.0.3",
"https://images.unsplash.com/photo-1496715976403-7e36dc43f17b?q=80&w=2848&auto=format&fit=crop&ixlib=rb-4.0.3",
"https://images.unsplash.com/photo-1600431521340-491eca880813?q=80&w=2938&auto=format&fit=crop&ixlib=rb-4.0.3",
],
randomCount: 10,
onVideoBackgroundUpdate: ({ backgroundMode, backgroundURL }) => {
console.log("videoBackgroundUpdated => ", {
backgroundMode,
backgroundURL,
});
},
});
const customControlBarButton = new CustomControlbarButton({
position: "left",
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M12 17.75a1.25 1.25 0 1 1 0 2.5a1.25 1.25 0 0 1 0-2.5zM12 14c0-2.5 4-2.5 4-6a4 4 0 1 0-8 0" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>',
label: "Click Me!",
onClick: () => alert("Custom Control Bar Button Clicked"),
});
// Register addons
const newConfig = registerAddons(
[
cameraHostControl,
micHostControl,
chatHostControl,
handRaise,
reactionsAddon,
participantTileMenu,
participantMenuItem,
participantsTabAction,
participantsTabToggle,
videoBackground,
customControlBarButton,
],
meeting,
);
setConfig(newConfig);
};
initializeAddons();
}, [meeting]);
return (
<RealtimeKitProvider value={meeting}>
<RtkMeeting showSetupScreen={true} meeting={meeting} config={config} />
</RealtimeKitProvider>
);
}
Note
If you are using RtkUiProvider instead of the RtkMeeting, pass the meeting and config objects to the provider:
<RtkUiProvider meeting={meeting} config={config}>
{/* Your custom UI components here */}
</RtkUiProvider>
Add the UI Kit library to your HTML:
<script type="module">
import { defineCustomElements } from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui@latest/loader/index.es2017.js";
defineCustomElements();
</script>
Place the rtk-meeting component in your HTML file:
<body>
<rtk-meeting></rtk-meeting>
</body>
Initialize the meeting and configure addons in your script:
```html <script type="module"> import RealtimeKitClient from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit@latest/dist/index.es.js"; import { registerAddons } from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui@latest/dist/index.es.js";
// Import addons import CameraHostControl from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/camera-host-control/index.js"; import MicHostControl from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/mic-host-control/index.js"; import ChatHostControl from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/chat-host-control/index.js"; import HandRaise from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/hand-raise/index.js"; import ReactionsManagerAddon from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/reactions-manager/index.js"; import ParticipantTileMenu from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/participant-tile-menu/index.js"; import ParticipantMenuItem from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/participant-menu-item/index.js"; import ParticipantsTabAction from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/participants-tab-action/index.js"; import ParticipantsTabToggle from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/participants-tab-toggle/index.js"; import RealtimeKitVideoBackground from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/video-background/index.js"; import CustomControlbarButton from "https://cdn.jsdelivr.net/npm/@cloudflare/realtimekit-ui-addons@latest/custom-controlbar-button/index.js";
// Initialize meeting const meeting = await RealtimeKitClient.init({ authToken: "<participant_auth_token>", });
// Initialize addons // Host controls const cameraHostControl = await CameraHostControl.init({ meeting, hostPresets: ["webinar_presenter"], targetPresets: ["webinar_viewer"], addActionInParticipantMenu: true, });
const micHostControl = await MicHostControl.init({ meeting, hostPresets: ["webinar_presenter"], targetPresets: ["webinar_viewer"], addActionInParticipantMenu: true, });
const chatHostControl = await ChatHostControl.init({ meeting, hostPresets: ["webinar_presenter"], targetPresets: ["webinar_viewer"], addActionInParticipantMenu: true, });
// Reactions const handRaise = await HandRaise.init({ meeting, canRaiseHand: true, canManageRaisedHand: true, handRaiseIcon: '<svg fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M4 12.02c0 1.06.2 2.1.6 3.08l.6 1.42c.22.55.64 1.01 1.17 1.29.27.14.56.21.86.21h2.55c.77 0 1.49-.41 1.87-1.08.5-.87 1.02-1.7 1.72-2.43l1.32-1.39c.44-.46.97-.84 1.49-1.23l.59-.45a.6.6 0 0 0 .23-.47c0-.75-.54-1.57-1.22-1.79a3.34 3.34 0 0 0-2.78.29V4.5a1.5 1.5 0 0 0-2.05-1.4 1.5 1.5 0 0 0-2.9 0A1.5 1.5 0 0 0 6 4.5v.09A1.5 1.5 0 0 0 4 6v6.02ZM8 4.5v4a.5.5 0 0 0 1 0v-5a.5.5 0 0 1 1 0v5a.5.5 0 0 0 1 0v-4a.5.5 0 0 1 1 0v6a.5.5 0 0 0 .85.37h.01c.22-.22.44-.44.72-.58.7-.35 2.22-.57 2.4.5l-.53.4c-.52.4-1.04.78-1.48 1.24l-1.33 1.38c-.75.79-1.31 1.7-1.85 2.63-.21.36-.6.58-1.01.58H7.23a.87.87 0 0 1-.4-.1 1.55 1.55 0 0 1-.71-.78l-.59-1.42a7.09 7.09 0 0 1-.53-2.7V6a.5.5 0 0 1 1 0v3.5a.5.5 0 0 0 1 0v-5a.5.5 0 0 1 1 0Z" fill="#ff0000"></path></svg>', });
const CUSTOM_REACTIONS = [ { emoji: "🔥", label: "fire" }, { emoji: "😢", label: "sad" }, { emoji: "👍", label: "thumbs up" }, { emoji: "👎", label: "thumbs down" }, { emoji: "❤️", label: "heart" }, { emoji: "😂", label: "laugh" }, { emoji: "👏", label: "clap" }, { emoji: "🎉", label: "celebrate" }, ];
const reactionsAddon = await ReactionsManagerAddon.init({ meeting, reactions: CUSTOM_REACTIONS, canSendReactions: true, });
// Participant Tile const participantTileMenu = new ParticipantTileMenu( [ { label: "Custom Toggle", onClick: (participantId) => { console.log("Clicked on custom toggle for ", participantId); }, }, ], "top-right", );
