PreJoin is the pre-call green-room gate. It owns the getUserMedia preview, the device enumeration loop, the live mic VU meter, and the name input — your app just receives the chosen options and runs its room-join sequence.
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 { PreJoin } from '@levelchat/react-components';
export function GreenRoom({ onJoinRoom }) {
return (
<PreJoin
title="Ready to join?"
subtitle="Daily standup · 8 already in"
initialDisplayName=""
onJoin={(opts) => onJoinRoom(opts)}
/>
);
}Headless hook
Use usePreJoin when you want a wholly bespoke green-room layout. The hook manages the preview lifecycle and returns ready-to-bind state:
import { usePreJoin } from '@levelchat/react-components';
function CustomGreenRoom() {
const { preview, devices, name, setName, micOn, setMicOn, ready, join } = usePreJoin();
return (
<>
<video ref={preview.videoRef} playsInline muted />
<input value={name} onChange={(e) => setName(e.target.value)} />
<button disabled={!ready} onClick={() => onJoinRoom(join())}>Join</button>
</>
);
}Slot composition
<PreJoin onJoin={join}>
<PreJoin.Preview />
<PreJoin.NameInput label="Display name" />
<PreJoin.DeviceMenu kind="mic" />
<PreJoin.DeviceMenu kind="camera" />
<PreJoin.DeviceMenu kind="speaker" />
<PreJoin.MicLevel />
<PreJoin.JoinButton>Join meeting</PreJoin.JoinButton>
</PreJoin>Theming
--lc-brand-primary— Join button background + VU meter bars.--lc-surface-base,--lc-border-default— form card.--lc-text-primary,--lc-text-secondary— copy.
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
onJoin | (opts: PreJoinJoinOptions) => void | Promise<void> | — | Called when the user submits. Required. |
initialDisplayName | string | '' | Pre-fill the name field. |
title | string | Ready to join? | Headline above the form. |
subtitle | string | — | Optional subtitle / topic. |
state | PreJoinState | — | Inject your own hook output (tests, Storybook). |