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/webBasic usage
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). |