ReactionBar is the picker a participant taps to send a reaction. ReactionOverlay renders reactions coming the other way — together they are the full round-trip. The bar auto-wires to the active room; pass onReact to use it without one.
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:
// 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:
// src/main.tsx
import '@levelchat/brand/tokens.css';
import '@levelchat/react-components/styles.css';Basic usage
Drop it inside a <LevelChatProvider> and every tap calls room.reactions.send(). The glass surface floats over the video stage; plain sits on a light card.
import { ReactionBar } from '@levelchat/react-components';
<ReactionBar surface="glass" />Pairing with ReactionOverlay
The two reaction components share one hook (useReactions), so wiring both gives you the complete loop — picker in, floating emoji out:
<div className="relative">
<ParticipantGrid />
<ReactionOverlay /> {/* incoming reactions */}
<div className="absolute bottom-4 inset-x-0 flex justify-center">
<ReactionBar surface="glass" /> {/* outgoing reactions */}
</div>
</div>Custom reaction set
The default set is six reactions. Pass reactions to curate your own — each entry needs an emoji and a human-readable label (the label drives the button's accessible name).
<ReactionBar
reactions={[
{ emoji: '👍', label: 'Agree' },
{ emoji: '🙌', label: 'Celebrate' },
{ emoji: '🤔', label: 'Thinking' },
]}
/>Headless hook
useReactions is the headless layer — build a wholly custom picker against its send action.
import { useReactions } from '@levelchat/react-components';
function MyPicker() {
const { send, supported } = useReactions();
if (!supported) return null;
return <button onClick={() => send('🎉')}>Celebrate</button>;
}Accessibility
- The bar is a
role="group"labelled "Send a reaction". - Each button has a real
aria-label("React with Applause") so the reaction is announced by name, never as a bare emoji glyph. - The tap-pop animation is suppressed under `prefers-reduced-motion`.
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
reactions | ReactionChoice[] | DEFAULT_REACTIONS | The emoji + label pairs to render. |
surface | 'glass' | 'plain' | glass | Translucent over-video bar, or opaque on-surface card. |
disabled | boolean | false | Disable every button. |
onReact | (emoji: string) => void | — | Called on every tap, alongside the room send. |