ParticipantGrid is the canonical meeting layout — every participant in a responsive grid that auto-scales from 1×1 up to 4×4, with the rest paginated. Local participant always slot 0, active speakers float upward.
Install
pnpm add @levelchat/react-components @levelchat/webRequirements
- React —
reactandreact-dom^18 || ^19(peer dependency). - LevelChat Web SDK —
@levelchat/web^0.2.4(peer dependency, wires hook-driven mode to the live Room). - Provider — wrap the tree in
<LevelChatProvider>from@levelchat/web-reactso hook-driven mode can subscribe to room events. Prop-driven demos work without it. - Styles — import the brand tokens + kit stylesheet exactly once at the app entry, before any kit component renders.
In Next.js (App Router), import the stylesheets at the top of your root layout:
TypeScript (TSX)
// app/layout.tsx
import '@levelchat/brand/tokens.css';
import '@levelchat/react-components/styles.css';In Vite (or any plain React app), import them at the top of your entry module:
TypeScript (TSX)
// src/main.tsx
import '@levelchat/brand/tokens.css';
import '@levelchat/react-components/styles.css';Basic usage
TypeScript (TSX)
import { ParticipantGrid } from '@levelchat/react-components';
export function MeetingStage() {
return <ParticipantGrid maxVisible={16} />;
}Headless hook
Use useParticipants when you want a custom layout. It returns a stable, sorted array (local first, then speaking-time descending, then join time):
import { useParticipants, VideoTile } from '@levelchat/react-components';
function MyGrid() {
const participants = useParticipants();
return (
<div className="grid grid-cols-4 gap-2">
{participants.map((p) => (
<VideoTile key={p.id} participantId={p.id} name={p.displayName ?? undefined} />
))}
</div>
);
}Sorting + pagination
- Stable sort: local → speaking → joined-at ascending.
- Batch SDK deltas via
useSyncExternalStore— no flicker when two participants join in the same WebSocket frame. - Overflow beyond
maxVisiblerenders a "+N more" tile that opens a pagination drawer (or is dropped entirely whenoverflow="hide").
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
maxVisible | number | 16 | Max tiles rendered before overflow kicks in. |
overflow | 'paginate' | 'hide' | paginate | What to do when participant count exceeds maxVisible. |
cornerRadius | number | — | Per-tile corner radius override. |
className | string | — | Override the grid container styling. |