Overview

The SessionManager 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

The SessionManager 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

Dependencies

The SessionManager component uses these external libraries:

  • PrimeReact: For dialog components
  • QRCode.react: For QR code generation
  • PrimeIcons: For UI icons

These dependencies are included with React Together and don’t need separate installation.

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>
  )
}