Overview
TheSessionManager component provides a pre-built UI for managing collaboration sessions. It offers a floating button that opens a dialog with options to create new sessions, share join URLs with QR codes, and leave current sessions. This component is perfect for applications that need easy session management without custom UI development.
Perfect for: Demo applications, prototypes, collaborative tools, and any app that needs quick session management without building custom UI.
Basic Usage
import { SessionManager } from 'react-together'
function MyApp() {
return (
<div className="app">
{/* Your main app content */}
<main>
<h1>My Collaborative App</h1>
<div className="content">
{/* App content goes here */}
</div>
</main>
{/* Session manager button - typically in a corner */}
<div className="fixed bottom-4 right-4">
<SessionManager />
</div>
</div>
)
}
Features
The SessionManager provides these built-in features:🔄 Session Creation
- Create new random sessions instantly
- Automatic session switching
- No manual configuration required
🔗 URL Sharing
- Copy session join URLs to clipboard
- Visual feedback when URLs are copied
- Shareable links for easy team joining
📱 QR Code Generation
- Generate QR codes for mobile sharing
- Toggle QR code display
- Perfect for cross-device collaboration
🚪 Session Management
- Leave current sessions
- Clean disconnect handling
- Automatic UI state updates
Props
TheSessionManager component takes no props - it’s completely self-contained and manages its own state.
Examples
Basic Implementation
Simple session manager for a collaborative workspace:import { SessionManager, useIsTogether, useConnectedUsers } from 'react-together'
function CollaborativeWorkspace() {
const isTogether = useIsTogether()
const connectedUsers = useConnectedUsers()
return (
<div className="workspace">
<header className="workspace-header">
<h1>Team Workspace</h1>
<div className="connection-status">
{isTogether ? (
<span className="connected">
✅ Connected ({connectedUsers.length} users)
</span>
) : (
<span className="disconnected">
❌ Not connected
</span>
)}
</div>
</header>
<main className="workspace-content">
<div className="document-area">
<h2>Shared Document</h2>
<p>Start collaborating with your team...</p>
</div>
<div className="sidebar">
<h3>Team Members</h3>
<ul>
{connectedUsers.map(user => (
<li key={user.userId}>
{user.nickname || `User ${user.userId.slice(0, 8)}`}
</li>
))}
</ul>
</div>
</main>
{/* Session manager in bottom-right corner */}
<SessionManager />
</div>
)
}
Dashboard Integration
Integrate session manager into a dashboard layout:import { SessionManager, useIsTogether, useJoinUrl } from 'react-together'
function Dashboard() {
const isTogether = useIsTogether()
const joinUrl = useJoinUrl()
return (
<div className="dashboard">
<nav className="dashboard-nav">
<h1>Project Dashboard</h1>
<div className="nav-actions">
{isTogether && (
<div className="session-info">
<span className="session-indicator">
🔗 Session Active
</span>
<span className="session-url">
{joinUrl ? `${joinUrl.slice(0, 30)}...` : 'Loading...'}
</span>
</div>
)}
</div>
</nav>
<div className="dashboard-content">
<div className="dashboard-cards">
<div className="card">
<h3>Tasks</h3>
<p>Collaborative task management</p>
</div>
<div className="card">
<h3>Files</h3>
<p>Shared file workspace</p>
</div>
<div className="card">
<h3>Chat</h3>
<p>Team communication</p>
</div>
</div>
</div>
{/* Session manager integrated into corner */}
<div className="session-manager-container">
<SessionManager />
</div>
</div>
)
}
Demo Application
Perfect for demo applications and prototypes:import { SessionManager, useIsTogether, useStateTogether, useConnectedUsers } from 'react-together'
function DemoApp() {
const isTogether = useIsTogether()
const connectedUsers = useConnectedUsers()
const [demoState, setDemoState] = useStateTogether('demo-state', {
clicks: 0,
message: 'Hello World!'
})
return (
<div className="demo-app">
<div className="demo-header">
<h1>🚀 React Together Demo</h1>
<div className="demo-stats">
<div className="stat">
<label>Status:</label>
<span className={isTogether ? 'connected' : 'disconnected'}>
{isTogether ? '🟢 Connected' : '🔴 Disconnected'}
</span>
</div>
<div className="stat">
<label>Users:</label>
<span>{connectedUsers.length}</span>
</div>
</div>
</div>
<div className="demo-content">
<div className="demo-section">
<h2>Shared Counter</h2>
<div className="counter-display">
<span className="counter-value">{demoState.clicks}</span>
<button
onClick={() => setDemoState(prev => ({ ...prev, clicks: prev.clicks + 1 }))}
className="counter-button"
>
Click Me! (+1)
</button>
</div>
</div>
<div className="demo-section">
<h2>Shared Message</h2>
<input
type="text"
value={demoState.message}
onChange={(e) => setDemoState(prev => ({ ...prev, message: e.target.value }))}
placeholder="Type a shared message..."
className="demo-input"
/>
</div>
<div className="demo-section">
<h2>Connected Users</h2>
<div className="user-list">
{connectedUsers.map(user => (
<div key={user.userId} className="user-card">
<div className="user-avatar">
{user.nickname ? user.nickname[0].toUpperCase() : '?'}
</div>
<span className="user-name">
{user.nickname || `User ${user.userId.slice(0, 8)}`}
</span>
</div>
))}
</div>
</div>
</div>
{/* Session manager for easy demo sharing */}
<SessionManager />
</div>
)
}
Mobile-Friendly Implementation
Responsive session manager for mobile devices:import { SessionManager, useIsTogether } from 'react-together'
import { useState, useEffect } from 'react'
function MobileApp() {
const isTogether = useIsTogether()
const [isMobile, setIsMobile] = useState(false)
useEffect(() => {
const checkMobile = () => {
setIsMobile(window.innerWidth < 768)
}
checkMobile()
window.addEventListener('resize', checkMobile)
return () => window.removeEventListener('resize', checkMobile)
}, [])
return (
<div className="mobile-app">
<div className="mobile-header">
<h1>Mobile Collab</h1>
<div className="status-indicator">
{isTogether ? '🟢' : '🔴'}
</div>
</div>
<div className="mobile-content">
<div className="content-card">
<h2>Collaboration Space</h2>
<p>Share this session with your team using the session button below.</p>
{isMobile && (
<div className="mobile-tip">
💡 Tap the React Together button to share via QR code
</div>
)}
</div>
<div className="mobile-workspace">
<textarea
placeholder="Collaborative notes..."
className="mobile-textarea"
rows={8}
/>
</div>
</div>
{/* Position session manager for mobile */}
<div
className={`session-manager-mobile ${isMobile ? 'mobile' : 'desktop'}`}
style={{
position: 'fixed',
bottom: isMobile ? '20px' : '16px',
right: isMobile ? '20px' : '16px',
zIndex: 1000
}}
>
<SessionManager />
</div>
</div>
)
}
Workshop/Training Application
Use session manager for educational or training applications:import { SessionManager, useIsTogether, useStateTogether, useConnectedUsers } from 'react-together'
function WorkshopApp() {
const isTogether = useIsTogether()
const connectedUsers = useConnectedUsers()
const [workshopState, setWorkshopState] = useStateTogether('workshop', {
currentSlide: 0,
questions: [] as string[],
polls: {} as Record<string, number>
})
const slides = [
{ title: "Welcome", content: "Welcome to our collaborative workshop!" },
{ title: "Introduction", content: "Let's learn together" },
{ title: "Interactive Exercise", content: "Everyone participate!" },
{ title: "Q&A", content: "Questions and answers" }
]
return (
<div className="workshop-app">
<div className="workshop-header">
<h1>📚 Collaborative Workshop</h1>
<div className="workshop-controls">
<div className="participant-count">
👥 {connectedUsers.length} participants
</div>
<div className="connection-status">
{isTogether ? '🟢 Live' : '🔴 Offline'}
</div>
</div>
</div>
<div className="workshop-content">
<div className="slide-area">
<div className="slide-header">
<h2>{slides[workshopState.currentSlide].title}</h2>
<div className="slide-navigation">
<button
onClick={() => setWorkshopState(prev => ({
...prev,
currentSlide: Math.max(0, prev.currentSlide - 1)
}))}
disabled={workshopState.currentSlide === 0}
>
← Previous
</button>
<span className="slide-counter">
{workshopState.currentSlide + 1} / {slides.length}
</span>
<button
onClick={() => setWorkshopState(prev => ({
...prev,
currentSlide: Math.min(slides.length - 1, prev.currentSlide + 1)
}))}
disabled={workshopState.currentSlide === slides.length - 1}
>
Next →
</button>
</div>
</div>
<div className="slide-content">
<p>{slides[workshopState.currentSlide].content}</p>
{workshopState.currentSlide === 2 && (
<div className="interactive-poll">
<h3>Quick Poll: How are you feeling?</h3>
<div className="poll-options">
{['😊 Great', '😐 Okay', '😴 Tired'].map(option => (
<button
key={option}
onClick={() => {
const currentVotes = workshopState.polls[option] || 0
setWorkshopState(prev => ({
...prev,
polls: {
...prev.polls,
[option]: currentVotes + 1
}
}))
}}
className="poll-button"
>
{option} ({workshopState.polls[option] || 0})
</button>
))}
</div>
</div>
)}
</div>
</div>
<div className="participant-panel">
<h3>Participants</h3>
<div className="participant-list">
{connectedUsers.map(user => (
<div key={user.userId} className="participant">
<div className="participant-avatar">
{user.nickname ? user.nickname[0].toUpperCase() : '?'}
</div>
<span className="participant-name">
{user.nickname || `Participant ${user.userId.slice(0, 6)}`}
</span>
</div>
))}
</div>
<div className="session-instructions">
<h4>Share Session</h4>
<p>Use the React Together button to share this workshop session with others.</p>
</div>
</div>
</div>
{/* Session manager for workshop sharing */}
<SessionManager />
</div>
)
}
Game Lobby
Use session manager for multiplayer game lobbies:import { SessionManager, useIsTogether, useStateTogether, useConnectedUsers } from 'react-together'
function GameLobby() {
const isTogether = useIsTogether()
const connectedUsers = useConnectedUsers()
const [gameState, setGameState] = useStateTogether('game-lobby', {
gameStarted: false,
players: [] as Array<{id: string, ready: boolean, score: number}>,
gameMode: 'classic'
})
const myUser = connectedUsers.find(u => u.userId === 'current-user-id') // This would be from useMyId()
const toggleReady = () => {
setGameState(prev => ({
...prev,
players: prev.players.map(p =>
p.id === myUser?.userId ? { ...p, ready: !p.ready } : p
)
}))
}
return (
<div className="game-lobby">
<div className="lobby-header">
<h1>🎮 Game Lobby</h1>
<div className="lobby-info">
<span className="player-count">
{connectedUsers.length} / 4 players
</span>
<span className="connection-status">
{isTogether ? '🟢 Connected' : '🔴 Disconnected'}
</span>
</div>
</div>
<div className="lobby-content">
<div className="player-section">
<h2>Players</h2>
<div className="player-grid">
{connectedUsers.map(user => {
const playerState = gameState.players.find(p => p.id === user.userId)
return (
<div key={user.userId} className="player-card">
<div className="player-avatar">
{user.nickname ? user.nickname[0].toUpperCase() : '?'}
</div>
<div className="player-info">
<span className="player-name">
{user.nickname || `Player ${user.userId.slice(0, 6)}`}
</span>
<span className={`player-status ${playerState?.ready ? 'ready' : 'not-ready'}`}>
{playerState?.ready ? '✅ Ready' : '⏳ Not Ready'}
</span>
</div>
</div>
)
})}
</div>
</div>
<div className="game-controls">
<h2>Game Settings</h2>
<div className="game-options">
<div className="option-group">
<label>Game Mode:</label>
<select
value={gameState.gameMode}
onChange={(e) => setGameState(prev => ({
...prev,
gameMode: e.target.value
}))}
>
<option value="classic">Classic</option>
<option value="speed">Speed Mode</option>
<option value="team">Team Battle</option>
</select>
</div>
</div>
<div className="lobby-actions">
<button
onClick={toggleReady}
className={`ready-button ${gameState.players.find(p => p.id === myUser?.userId)?.ready ? 'ready' : ''}`}
>
{gameState.players.find(p => p.id === myUser?.userId)?.ready ? 'Not Ready' : 'Ready Up!'}
</button>
<button
onClick={() => setGameState(prev => ({ ...prev, gameStarted: true }))}
disabled={gameState.players.length < 2 || !gameState.players.every(p => p.ready)}
className="start-game-button"
>
Start Game
</button>
</div>
</div>
<div className="lobby-chat">
<h3>Lobby Chat</h3>
<div className="chat-placeholder">
<p>Chat integration would go here...</p>
</div>
</div>
</div>
{/* Session manager for inviting players */}
<SessionManager />
</div>
)
}
Event/Meeting Application
Session manager for virtual events and meetings:import { SessionManager, useIsTogether, useConnectedUsers } from 'react-together'
function VirtualEvent() {
const isTogether = useIsTogether()
const connectedUsers = useConnectedUsers()
return (
<div className="virtual-event">
<div className="event-header">
<h1>🎪 Virtual Event</h1>
<div className="event-info">
<span className="event-time">
📅 Today at 2:00 PM
</span>
<span className="attendee-count">
👥 {connectedUsers.length} attendees
</span>
</div>
</div>
<div className="event-content">
<div className="main-stage">
<div className="presentation-area">
<h2>Welcome to Our Virtual Event!</h2>
<p>Join the conversation and connect with other attendees.</p>
<div className="stage-controls">
<button className="stage-button">
🎤 Join Stage
</button>
<button className="stage-button">
💬 Open Chat
</button>
<button className="stage-button">
🙋 Raise Hand
</button>
</div>
</div>
</div>
<div className="attendee-panel">
<h3>Attendees</h3>
<div className="attendee-list">
{connectedUsers.map(user => (
<div key={user.userId} className="attendee">
<div className="attendee-avatar">
{user.nickname ? user.nickname[0].toUpperCase() : '?'}
</div>
<span className="attendee-name">
{user.nickname || `Attendee ${user.userId.slice(0, 6)}`}
</span>
<span className="attendee-status">
{isTogether ? '🟢' : '🔴'}
</span>
</div>
))}
</div>
<div className="event-sharing">
<h4>Invite Others</h4>
<p>Share this event with colleagues and friends using the session manager.</p>
</div>
</div>
</div>
{/* Session manager for event sharing */}
<SessionManager />
</div>
)
}
Built-in Styling
The SessionManager includes built-in CSS styling with these classes:/* Session button */
.session-button {
display: flex;
align-items: center;
justify-content: center;
padding: 8px 12px;
border-radius: 1rem;
color: white;
background-color: #3b82f6;
border: 1px solid #2d3748;
box-shadow: 0 2px 0 #2d3748;
}
/* Dialog components */
.sessionMenuContent-container { /* Dialog content */ }
.input-container { /* URL input area */ }
.qrCode-container { /* QR code display */ }
Customization
While the SessionManager is designed to be used as-is, you can customize its appearance with CSS:/* Custom button styling */
.session-button {
background-color: #your-brand-color !important;
border-color: #your-border-color !important;
}
/* Custom dialog styling */
.p-dialog .p-dialog-content {
background-color: #your-background-color;
}
/* Custom input styling */
.input-container {
background-color: #your-input-background;
border-color: #your-input-border;
}
Best Practices
Positioning
// ✅ Good - Fixed positioning in corner
<div className="fixed bottom-4 right-4 z-50">
<SessionManager />
</div>
// ✅ Good - Integrated into layout
<div className="app-controls">
<SessionManager />
</div>
Mobile Considerations
// ✅ Good - Responsive positioning
<div className={`session-manager ${isMobile ? 'mobile' : 'desktop'}`}>
<SessionManager />
</div>
User Experience
// ✅ Good - Provide context
<div className="session-area">
<p>Use the React Together button to share this session</p>
<SessionManager />
</div>
Common Use Cases
- Demo Applications: Quick session sharing for demonstrations
- Prototypes: Easy collaboration without custom UI
- Educational Tools: Workshop and training session management
- Gaming: Multiplayer game lobby management
- Events: Virtual event and meeting coordination
- Team Tools: Quick team collaboration setup
Related Components
ReactTogether- Main context providerChat- Real-time chat componentConnectedUsers- User display component
Related Hooks
useCreateRandomSession- Create new sessionsuseJoinUrl- Get session join URLsuseLeaveSession- Leave current sessionuseIsTogether- Check connection status
Dependencies
The SessionManager component uses these external libraries:- PrimeReact: For dialog components
- QRCode.react: For QR code generation
- PrimeIcons: For UI icons
TypeScript Support
The SessionManager component is fully typed and requires no additional type definitions:import { SessionManager } from 'react-together'
// No props needed - fully self-contained
function MyApp() {
return (
<div>
<SessionManager />
</div>
)
}