fix: add ui component gallery (#27376)

* fix: add ui component gallery

* fix: add dark mode colours

* fix: fix asset path

* fix: update image path

* fix: update image imports
This commit is contained in:
Ishita Kabra 2026-01-08 10:48:42 +05:30 committed by GitHub
parent b65f0d4b60
commit aa6f6daf48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 637 additions and 277 deletions

View file

@ -30,12 +30,12 @@ export default function SDKSelector() {
return (
<>
<div className="my-5 flex flex-col gap-0 rounded-md bg-blue-100 p-2 dark:bg-neutral-800">
<div className="my-5 flex flex-col gap-0 rounded-sm bg-blue-50 p-2 dark:bg-neutral-800">
<div className="flex w-full flex-row items-start justify-start gap-2">
{platforms.map((p) => (
<button
type="button"
className={`m-0 ${p.id === platform ? "rounded-t-md bg-neutral-50 text-blue-500 dark:bg-neutral-700" : "bg-blue-100 text-neutral-700 dark:bg-neutral-800 dark:text-neutral-300"} px-2 py-1 font-medium`}
className={`m-0 ${p.id === platform ? "rounded-t-md bg-white font-semibold text-blue-800 dark:bg-neutral-700 dark:text-blue-100" : "bg-blue-50 text-neutral-800 dark:bg-neutral-800 dark:text-neutral-300"} cursor-pointer px-2 py-1 font-medium`}
onClick={() => {
const nextPlatform = p.id;
const nextFramework =
@ -52,11 +52,11 @@ export default function SDKSelector() {
))}
</div>
{frameworks.length < 1 && (
<div className="m-0 w-full rounded-r-md rounded-b-md bg-neutral-50 p-4 text-sm text-gray-500 italic dark:bg-neutral-700 dark:text-gray-400">
<div className="m-0 w-full rounded-r-md rounded-b-md bg-white p-4 text-sm text-gray-500 italic dark:bg-neutral-700 dark:text-gray-400">
No frameworks available.
</div>
)}
<div className="m-0 flex w-full flex-row items-center gap-2 rounded-r-md rounded-b-md bg-neutral-50 p-2 text-gray-500 dark:bg-neutral-700 dark:text-gray-400">
<div className="m-0 flex w-full flex-row items-center gap-2 rounded-r-md rounded-b-md bg-white p-2 text-gray-500 dark:bg-neutral-700 dark:text-gray-400">
{frameworks.map((fw) => {
const handleClick = () => {
setSelection(platform, fw);
@ -66,7 +66,7 @@ export default function SDKSelector() {
<button
key={fw.id}
type="button"
className={`m-0 flex ${framework?.id === fw.id ? "text-blue-500 italic" : ""} text-md cursor-pointer items-center rounded-md bg-neutral-50 px-3 py-1 font-medium dark:bg-neutral-700`}
className={`m-0 flex ${framework?.id === fw.id ? "font-semibold text-blue-800 dark:text-blue-100" : ""} text-md cursor-pointer items-center rounded-md bg-white px-3 py-1 font-medium dark:bg-neutral-700`}
onClick={handleClick}
>
{fw.label}

View file

@ -0,0 +1,24 @@
---
interface Props {
id: string;
name: string;
imagePath: string;
componentName: string;
}
const { name, imagePath, componentName, id } = Astro.props;
import UIComponent from "./RTKUIComponent.tsx";
// Convert ~ alias to proper import path for Astro
const resolvedImagePath = imagePath.startsWith("~/")
? imagePath.replace("~/", "/src/")
: imagePath;
---
<UIComponent
client:load
id={id}
name={name}
imagePath={resolvedImagePath}
componentName={componentName}
/>

View file

@ -0,0 +1,95 @@
interface Props {
id: string;
name: string;
imagePath: string;
componentName: string;
}
import { useMemo, useState } from "react";
import { useFramework } from "../hooks/useFramework";
const kebabToPascalCase = (str: string): string => {
return str
.split("-")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join("");
};
const RTKUIComponent = ({ id, imagePath, name, componentName }: Props) => {
const [isExpanded, setIsExpanded] = useState(false);
const { platform, framework } = useFramework();
const component = useMemo(() => {
if (platform !== "web") return componentName;
if (framework.id === "react") return kebabToPascalCase(componentName);
return componentName;
}, [platform, framework, componentName]);
const toggleImageSize = () => {
setIsExpanded(!isExpanded);
};
return (
<div className="mt-2 flex flex-col items-center gap-3" id={id}>
{!isExpanded && (
<div className="relative">
<img
src={imagePath}
alt={name}
style={{ border: "solid 1px #ccc", width: "200px" }}
className={`w-full rounded-md transition-all duration-300 ease-in-out`}
/>
<button
onClick={toggleImageSize}
style={{ border: "solid 4px #fff" }}
className={`absolute bottom-0 left-0 flex h-8 w-8 cursor-pointer items-center justify-center rounded-md p-1 text-black`}
>
</button>
</div>
)}
{isExpanded && (
<div
className="flex flex-col items-center gap-4 rounded-md p-4"
style={{
width: "100%",
background: "white",
border: "solid 1px #ccc",
}}
>
<div className="relative">
<img
src={imagePath}
alt={name}
style={{
border: "solid 1px #ccc",
width: "100%",
height: "500px",
}}
className={`w-full rounded-md transition-all duration-300 ease-in-out`}
/>
<button
onClick={toggleImageSize}
style={{ border: "solid 4px #fff" }}
className={`absolute bottom-0 left-0 flex h-8 w-8 cursor-pointer items-center justify-center rounded-md p-1 text-black`}
>
</button>
</div>
<code className="w-fit rounded-sm bg-gray-100 p-1 dark:bg-neutral-700">
{component}
</code>
</div>
)}
{!isExpanded && (
<code className="w-fit rounded-sm bg-gray-100 p-1 dark:bg-neutral-700">
{component}
</code>
)}
</div>
);
};
export default RTKUIComponent;

View file

@ -0,0 +1,5 @@
---
import UIComponentGrid from "./RTKUIComponentGrid.tsx";
---
<UIComponentGrid client:load />

View file

@ -0,0 +1,502 @@
import { useState, useMemo } from "react";
import RTKUIComponent from "../RTKUIComponent/RTKUIComponent";
const componentGalleryImageModules = import.meta.glob(
"../../../assets/images/realtime/realtimekit/web/components-gallery/*.svg",
{ eager: true },
);
const componentGalleryImageSrcByFileName = Object.fromEntries(
Object.entries(componentGalleryImageModules).map(([path, mod]) => {
const fileName = path.split("/").pop() as string;
const defaultExport = (mod as any).default;
const src = defaultExport?.src ?? defaultExport;
return [fileName, src];
}),
) as Record<string, string>;
const imageSrc = (fileName: string) =>
componentGalleryImageSrcByFileName[fileName];
const RTKUIComponentGrid = () => {
const [searchTerm, setSearchTerm] = useState("");
const basicComponents = [
{
id: "rtk-avatar",
name: "Avatar",
imagePath: imageSrc("rtk-avatar.svg"),
componentName: "rtk-avatar",
tags: ["participant", "tile", "grid"],
},
{
id: "rtk-audio-visualizer",
name: "Audio Visualizer",
imagePath: imageSrc("rtk-audio-visualizer.svg"),
componentName: "rtk-audio-visualizer",
tags: ["participant", "audio", "visualizer", "grid"],
},
{
id: "rtk-button",
name: "Button",
imagePath: imageSrc("rtk-button.svg"),
componentName: "rtk-button",
tags: ["button", "controlbar", "controlbar-button"],
},
{
id: "rtk-clock",
name: "Clock",
imagePath: imageSrc("rtk-clock.svg"),
componentName: "rtk-clock",
tags: ["clock", "header", "sidebar"],
},
{
id: "rtk-header",
name: "Header",
imagePath: imageSrc("rtk-header.svg"),
componentName: "rtk-header",
tags: ["header", "sidebar"],
},
{
id: "rtk-logo",
name: "Logo",
imagePath: imageSrc("rtk-logo.svg"),
componentName: "rtk-logo",
tags: ["logo", "header", "sidebar"],
},
{
id: "rtk-meeting-title",
name: "Meeting Title",
imagePath: imageSrc("rtk-meeting-title.svg"),
componentName: "rtk-meeting-title",
tags: ["meeting-title", "header", "sidebar"],
},
{
id: "rtk-recording-indicator",
name: "Recording Indicator",
imagePath: imageSrc("rtk-recording-indicator.svg"),
componentName: "rtk-recording-indicator",
tags: ["recording", "indicator", "header", "sidebar", "controlbar"],
},
{
id: "rtk-spinner",
name: "Spinner",
imagePath: imageSrc("rtk-spinner.svg"),
componentName: "rtk-spinner",
tags: ["spinner", "controlbar", "controlbar-button"],
},
{
id: "rtk-switch",
name: "Switch",
imagePath: imageSrc("rtk-switch.svg"),
componentName: "rtk-switch",
tags: ["switch", "controlbar", "button"],
},
{
id: "rtk-tooltip",
name: "Tooltip",
imagePath: imageSrc("rtk-tooltip.svg"),
componentName: "rtk-tooltip",
tags: ["tooltip", "controlbar", "button"],
},
];
const uiComponents = [
{
id: "rtk-controlbar",
name: "Control Bar",
imagePath: imageSrc("rtk-controlbar.svg"),
componentName: "rtk-controlbar",
tags: ["controlbar", "button"],
},
{
id: "rtk-controlbar-button",
name: "Control Bar Button",
imagePath: imageSrc("rtk-controlbar-button.svg"),
componentName: "rtk-controlbar-button",
tags: ["controlbar", "button"],
},
{
id: "rtk-dialog",
name: "Dialog",
imagePath: imageSrc("rtk-dialog.svg"),
componentName: "rtk-dialog",
tags: ["dialog", "modal", "popup"],
},
{
id: "rtk-emoji-picker",
name: "Emoji Picker",
imagePath: imageSrc("rtk-emoji-picker.svg"),
componentName: "rtk-emoji-picker",
tags: ["emoji-picker", "sidebar", "chat", "message"],
},
{
id: "rtk-grid-pagination",
name: "Grid Pagination",
imagePath: imageSrc("rtk-grid-pagination.svg"),
componentName: "rtk-grid-pagination",
tags: ["pagination", "grid", "participant", "tile", "header"],
},
{
id: "rtk-menu",
name: "Menu",
imagePath: imageSrc("rtk-menu.svg"),
componentName: "rtk-menu",
tags: ["menu", "sidebar", "controlbar", "button"],
},
{
id: "rtk-name-tag",
name: "Name Tag",
imagePath: imageSrc("rtk-name-tag.svg"),
componentName: "rtk-name-tag",
tags: ["name-tag", "participant", "tile", "grid"],
},
{
id: "rtk-notification",
name: "Notification",
imagePath: imageSrc("rtk-notification.svg"),
componentName: "rtk-notification",
tags: ["notification", "sidebar", "popup", "chat"],
},
{
id: "rtk-participant-count",
name: "Participant Count",
imagePath: imageSrc("rtk-participant-count.svg"),
componentName: "rtk-participant-count",
tags: ["participant-count", "header", "sidebar"],
},
{
id: "rtk-participant-tile",
name: "Participant Tile",
imagePath: imageSrc("rtk-participant-tile.svg"),
componentName: "rtk-participant-tile",
tags: ["participant-tile", "participant", "tile", "grid"],
},
{
id: "rtk-plugin-main",
name: "Plugin Main View",
imagePath: imageSrc("rtk-plugin-main.svg"),
componentName: "rtk-plugin-main",
tags: ["plugin-main", "plugin", "sidebar", "controlbar", "button"],
},
];
const compositeComponents = [
{
id: "rtk-chat",
name: "Chat",
imagePath: imageSrc("rtk-chat.svg"),
componentName: "rtk-chat",
tags: ["chat", "message", "sidebar"],
},
{
id: "rtk-grid",
name: "Grid",
imagePath: imageSrc("rtk-grid.svg"),
componentName: "rtk-grid",
tags: ["grid", "participant", "tile", "layout"],
},
{
id: "rtk-image-viewer",
name: "Image Viewer",
imagePath: imageSrc("rtk-image-viewer.svg"),
componentName: "rtk-image-viewer",
tags: ["image-viewer", "media", "chat", "sidebar"],
},
{
id: "rtk-leave-meeting",
name: "Leave Meeting",
imagePath: imageSrc("rtk-leave-meeting.svg"),
componentName: "rtk-leave-meeting",
tags: ["leave", "dialog", "modal", "controlbar", "button", "end"],
},
{
id: "rtk-mixed-grid",
name: "Mixed Grid",
imagePath: imageSrc("rtk-mixed-grid.svg"),
componentName: "rtk-mixed-grid",
tags: ["mixed", "grid", "participant", "tile", "layout"],
},
{
id: "rtk-participants",
name: "Participants",
imagePath: imageSrc("rtk-participants.svg"),
componentName: "rtk-participants",
tags: ["participants", "sidebar", "list", "participant", "tile"],
},
{
id: "rtk-participants-audio",
name: "Participants Audio",
imagePath: imageSrc("rtk-participants-audio.svg"),
componentName: "rtk-participants-audio",
tags: ["participants-audio", "audio", "sidebar", "participant", "list"],
},
{
id: "rtk-plugins",
name: "Plugins",
imagePath: imageSrc("rtk-plugins.svg"),
componentName: "rtk-plugins",
tags: ["plugins", "sidebar", "list", "plugin"],
},
{
id: "rtk-polls",
name: "Polls",
imagePath: imageSrc("rtk-polls.svg"),
componentName: "rtk-polls",
tags: ["polls", "sidebar", "voting", "interactive"],
},
{
id: "rtk-screenshare-view",
name: "Screenshare View",
imagePath: imageSrc("rtk-screenshare-view.svg"),
componentName: "rtk-screenshare-view",
tags: ["screenshare-view", "screenshare", "media", "grid"],
},
{
id: "rtk-settings",
name: "Settings",
imagePath: imageSrc("rtk-settings.svg"),
componentName: "rtk-settings",
tags: [
"settings",
"sidebar",
"configuration",
"preferences",
"dialog",
"modal",
],
},
{
id: "rtk-settings-audio",
name: "Settings Audio",
imagePath: imageSrc("rtk-settings-audio.svg"),
componentName: "rtk-settings-audio",
tags: [
"settings-audio",
"audio",
"settings",
"sidebar",
"configuration",
"dialog",
"modal",
],
},
{
id: "rtk-settings-video",
name: "Settings Video",
imagePath: imageSrc("rtk-settings-video.svg"),
componentName: "rtk-settings-video",
tags: [
"settings-video",
"video",
"settings",
"sidebar",
"configuration",
"dialog",
"modal",
],
},
{
id: "rtk-sidebar",
name: "Sidebar",
imagePath: imageSrc("rtk-sidebar.svg"),
componentName: "rtk-sidebar",
tags: ["sidebar", "layout", "navigation", "panel"],
},
{
id: "rtk-simple-grid",
name: "Simple Grid",
imagePath: imageSrc("rtk-simple-grid.svg"),
componentName: "rtk-simple-grid",
tags: ["simple", "grid", "participant", "tile", "layout", "basic"],
},
{
id: "rtk-spotlight-grid",
name: "Spotlight Grid",
imagePath: imageSrc("rtk-spotlight-grid.svg"),
componentName: "rtk-spotlight-grid",
tags: ["spotlight", "grid", "participant", "tile", "layout", "pinned"],
},
];
const screenComponents = [
{
id: "rtk-ended-screen",
name: "Ended Screen",
imagePath: imageSrc("rtk-ended-screen.svg"),
componentName: "rtk-ended-screen",
tags: ["ended", "screen", "meeting", "end", "leave"],
},
{
id: "rtk-idle-screen",
name: "Idle Screen",
imagePath: imageSrc("rtk-idle-screen.svg"),
componentName: "rtk-idle-screen",
tags: ["idle", "screen", "waiting", "lobby", "standby"],
},
{
id: "rtk-meeting",
name: "Meeting Screen",
imagePath: imageSrc("rtk-meeting.svg"),
componentName: "rtk-meeting",
tags: ["meeting", "screen", "main", "active"],
},
{
id: "rtk-setup-screen",
name: "Setup Screen",
imagePath: imageSrc("rtk-setup-screen.svg"),
componentName: "rtk-setup-screen",
tags: ["setup", "screen", "configuration", "preview"],
},
];
// Filter function to search through components
const filterComponents = (components: typeof basicComponents) => {
if (!searchTerm.trim()) return components;
const lowercaseSearch = searchTerm.toLowerCase();
return components.filter((component) => {
// Search in name
if (component.name.toLowerCase().includes(lowercaseSearch)) return true;
// Search in component name
if (component.componentName.toLowerCase().includes(lowercaseSearch))
return true;
// Search in tags
if (
component.tags.some((tag) =>
tag.toLowerCase().includes(lowercaseSearch),
)
)
return true;
return false;
});
};
// Filtered component arrays
const filteredBasicComponents = useMemo(
() => filterComponents(basicComponents),
[searchTerm],
);
const filteredUiComponents = useMemo(
() => filterComponents(uiComponents),
[searchTerm],
);
const filteredCompositeComponents = useMemo(
() => filterComponents(compositeComponents),
[searchTerm],
);
const filteredScreenComponents = useMemo(
() => filterComponents(screenComponents),
[searchTerm],
);
return (
<div>
<h2 className="mb-2 text-2xl font-bold">Component Gallery</h2>
<p className="mb-4">
Search through the comoponent gallery for the component you need.
</p>
<input
className="mb-2 w-full rounded-md border bg-neutral-50 p-1 px-2 dark:border-neutral-600 dark:bg-neutral-800"
placeholder="Search for 'Chat'"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
{/* Show no results message if search term exists but no components found */}
{searchTerm.trim() &&
filteredBasicComponents.length === 0 &&
filteredUiComponents.length === 0 &&
filteredCompositeComponents.length === 0 &&
filteredScreenComponents.length === 0 && (
<div className="py-8 text-center">
<p className="text-gray-500">
No components found for "{searchTerm}"
</p>
<p className="mt-2 text-sm text-gray-400">
Try searching for terms like "grid", "chat", "button", or
"settings"
</p>
</div>
)}
{/* Basic Components */}
{filteredBasicComponents.length > 0 && (
<>
<h2 className="mb-2 text-2xl font-bold">Basic Components</h2>
<p className="mb-4">Small, reusable building blocks for your UI.</p>
<div className="flex flex-wrap items-start gap-4">
{filteredBasicComponents.map((component) => (
<RTKUIComponent
key={component.id}
id={component.id}
name={component.name}
imagePath={component.imagePath}
componentName={component.componentName}
/>
))}
</div>
</>
)}
{/* UI Components */}
{filteredUiComponents.length > 0 && (
<>
<h2 className="mb-2 text-2xl font-bold">UI Components</h2>
<p className="mb-4">Interactive controls and interface elements.</p>
<div className="flex flex-wrap items-start gap-4">
{filteredUiComponents.map((component) => (
<RTKUIComponent
key={component.id}
id={component.id}
name={component.name}
imagePath={component.imagePath}
componentName={component.componentName}
/>
))}
</div>
</>
)}
{/* Composite Components */}
{filteredCompositeComponents.length > 0 && (
<>
<h2 className="mb-2 text-2xl font-bold">Composite Components</h2>
<p className="mb-4">
Complete, feature-rich components combining multiple elements.
</p>
<div className="flex flex-wrap items-start gap-4">
{filteredCompositeComponents.map((component) => (
<RTKUIComponent
key={component.id}
id={component.id}
name={component.name}
imagePath={component.imagePath}
componentName={component.componentName}
/>
))}
</div>
</>
)}
{/* Screen Components */}
{filteredScreenComponents.length > 0 && (
<>
<h2 className="mb-2 text-2xl font-bold">Screen Components</h2>
<p className="mb-4">
Full-screen views for different meeting states.
</p>
<div className="flex flex-wrap items-start gap-4">
{filteredScreenComponents.map((component) => (
<RTKUIComponent
key={component.id}
id={component.id}
name={component.name}
imagePath={component.imagePath}
componentName={component.componentName}
/>
))}
</div>
</>
)}
</div>
);
};
export default RTKUIComponentGrid;

View file

@ -6,13 +6,14 @@ sidebar:
order: 3
---
import { Tabs, TabItem } from "~/components";
<Tabs>
<TabItem syncKey="realtimeKitFrameworkTypeTabs" label="Web Frameworks">
import RTKSDKSelector from "~/components/realtimekit/RTKSDKSelector/RTKSDKSelector.astro";
import RTKUIComponent from "~/components/realtimekit/RTKUIComponent/RTKUIComponent.astro";
import RTKUIComponentGrid from "~/components/realtimekit/RTKUIComponentGrid/RTKUIComponentGrid.astro";
The UI Kit components library provides a comprehensive set of pre-built, customizable components that you can use to build your own custom meeting interface.
<RTKSDKSelector />
:::note
All UI Kit components are built on top of Web Components, regardless of which framework (React/Angular) you use. They render as Web Components in the browser DOM.
@ -24,271 +25,4 @@ All UI Kit components are built on top of Web Components, regardless of which fr
React and Angular components are wrappers around the same underlying Web Components, so functionality is identical across all frameworks.
:::
## Basic Components
Small, reusable building blocks for your UI.
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1.5rem; margin: 2rem 0;">
<div style="text-align: center;" id="rtk-audio-visualizer">
![Audio
Visualizer](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-audio-visualizer.svg)
`rtk-audio-visualizer`
</div>
<div style="text-align: center;" id="rtk-avatar">
![Avatar](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-avatar.svg)
`rtk-avatar`
</div>
<div style="text-align: center;" id="rtk-button">
![Button](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-button.svg)
`rtk-button`
</div>
<div style="text-align: center;" id="rtk-clock">
![Clock](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-clock.svg)
`rtk-clock`
</div>
<div style="text-align: center;" id="rtk-header">
![Header](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-header.svg)
`rtk-header`
</div>
<div style="text-align: center;" id="rtk-logo">
![Logo](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-logo.svg)
`rtk-logo`
</div>
<div style="text-align: center;" id="rtk-meeting-title">
![Meeting
Title](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-meeting-title.svg)
`rtk-meeting-title`
</div>
<div style="text-align: center;" id="rtk-recording-indicator">
![Recording
Indicator](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-recording-indicator.svg)
`rtk-recording-indicator`
</div>
<div style="text-align: center;" id="rtk-spinner">
![Spinner](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-spinner.svg)
`rtk-spinner`
</div>
<div style="text-align: center;" id="rtk-switch">
![Switch](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-switch.svg)
`rtk-switch`
</div>
<div style="text-align: center;" id="rtk-tooltip">
![Tooltip](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-tooltip.svg)
`rtk-tooltip`
</div>
</div>
## UI Components
Interactive controls and interface elements.
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1.5rem; margin: 2rem 0;">
<div style="text-align: center;" id="rtk-controlbar">
![Control
Bar](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-controlbar.svg)
`rtk-controlbar`
</div>
<div style="text-align: center;" id="rtk-controlbar-button">
![Control Bar
Button](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-controlbar-button.svg)
`rtk-controlbar-button`
</div>
<div style="text-align: center;" id="rtk-dialog">
![Dialog](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-dialog.svg)
`rtk-dialog`
</div>
<div style="text-align: center;" id="rtk-emoji-picker">
![Emoji
Picker](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-emoji-picker.svg)
`rtk-emoji-picker`
</div>
<div style="text-align: center;" id="rtk-grid-pagination">
![Grid
Pagination](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-grid-pagination.svg)
`rtk-grid-pagination`
</div>
<div style="text-align: center;" id="rtk-menu">
![Menu](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-menu.svg)
`rtk-menu`
</div>
<div style="text-align: center;" id="rtk-name-tag">
![Name
Tag](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-name-tag.svg)
`rtk-name-tag`
</div>
<div style="text-align: center;" id="rtk-notification">
![Notification](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-notification.svg)
`rtk-notification`
</div>
<div style="text-align: center;" id="rtk-participant-count">
![Participant
Count](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-participant-count.svg)
`rtk-participant-count`
</div>
<div style="text-align: center;" id="rtk-participant-tile">
![Participant
Tile](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-participant-tile.svg)
`rtk-participant-tile`
</div>
<div style="text-align: center;" id="rtk-plugin-main">
![Plugin Main
View](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-plugin-main.svg)
`rtk-plugin-main`
</div>
</div>
## Composite Components
Complete, feature-rich components combining multiple elements.
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1.5rem; margin: 2rem 0;">
<div style="text-align: center;" id="rtk-chat">
![Chat](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-chat.svg)
`rtk-chat`
</div>
<div style="text-align: center;" id="rtk-grid">
![Grid](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-grid.svg)
`rtk-grid`
</div>
<div style="text-align: center;" id="rtk-image-viewer">
![Image
Viewer](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-image-viewer.svg)
`rtk-image-viewer`
</div>
<div style="text-align: center;" id="rtk-leave-meeting">
![Leave
Meeting](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-leave-meeting.svg)
`rtk-leave-meeting`
</div>
<div style="text-align: center;" id="rtk-mixed-grid">
![Mixed
Grid](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-mixed-grid.svg)
`rtk-mixed-grid`
</div>
<div style="text-align: center;" id="rtk-participants">
![Participants](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-participants.svg)
`rtk-participants`
</div>
<div style="text-align: center;" id="rtk-participants-audio">
![Participants
Audio](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-participants-audio.svg)
`rtk-participants-audio`
</div>
<div style="text-align: center;" id="rtk-plugins">
![Plugins](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-plugins.svg)
`rtk-plugins`
</div>
<div style="text-align: center;" id="rtk-polls">
![Polls](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-polls.svg)
`rtk-polls`
</div>
<div style="text-align: center;" id="rtk-screenshare-view">
![Screenshare
View](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-screenshare-view.svg)
`rtk-screenshare-view`
</div>
<div style="text-align: center;" id="rtk-settings">
![Settings](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-settings.svg)
`rtk-settings`
</div>
<div style="text-align: center;" id="rtk-settings-audio">
![Settings
Audio](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-settings-audio.svg)
`rtk-settings-audio`
</div>
<div style="text-align: center;" id="rtk-settings-video">
![Settings
Video](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-settings-video.svg)
`rtk-settings-video`
</div>
<div style="text-align: center;" id="rtk-sidebar">
![Sidebar](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-sidebar.svg)
`rtk-sidebar`
</div>
<div style="text-align: center;" id="rtk-simple-grid">
![Simple
Grid](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-simple-grid.svg)
`rtk-simple-grid`
</div>
<div style="text-align: center;" id="rtk-spotlight-grid">
![Spotlight
Grid](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-spotlight-grid.svg)
`rtk-spotlight-grid`
</div>
</div>
## Screen Components
Full-screen views for different meeting states.
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1.5rem; margin: 2rem 0;">
<div style="text-align: center;" id="rtk-ended-screen">
![Ended
Screen](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-ended-screen.svg)
`rtk-ended-screen`
</div>
<div style="text-align: center;" id="rtk-idle-screen">
![Idle
Screen](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-idle-screen.svg)
`rtk-idle-screen`
</div>
<div style="text-align: center;" id="rtk-meeting">
![Meeting
Screen](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-meeting.svg)
`rtk-meeting`
</div>
<div style="text-align: center;" id="rtk-setup-screen">
![Setup
Screen](~/assets/images/realtime/realtimekit/web/components-gallery/rtk-setup-screen.svg)
`rtk-setup-screen`
</div>
</div>
</TabItem>
</Tabs>
<RTKUIComponentGrid />