Overview
useIsTogether
returns true
when the user is currently connected to a React Together session, and false
otherwise. This hook is essential for building connection-aware interfaces that adapt based on whether users are in a collaborative session.
Perfect for: Conditional rendering of collaborative features, connection status indicators, session-dependent logic, and graceful offline/online state handling.
Basic Usage
import { useIsTogether } from 'react-together'
function ConnectionStatus() {
const isTogether = useIsTogether()
return (
<div>
{isTogether ? (
<span className="text-green-600">✓ Connected to session</span>
) : (
<span className="text-gray-500">○ Not connected</span>
)}
</div>
)
}
Signature
Return Value
true
if the user is connected to a React Together session, false
otherwise
Examples
Session-Dependent Feature Toggle
Show different UI based on connection status:
import { useIsTogether, useStateTogether } from 'react-together'
function CollaborativeEditor() {
const isTogether = useIsTogether()
const [content, setContent] = useStateTogether('document', '')
return (
<div className="editor">
<div className="status-bar">
{isTogether ? (
<span className="collaborative-mode">
🤝 Collaborative Mode - Changes sync in real-time
</span>
) : (
<span className="offline-mode">
📝 Offline Mode - Changes saved locally
</span>
)}
</div>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder={
isTogether
? "Start typing to collaborate..."
: "Connect to session to collaborate"
}
className={isTogether ? 'border-green-300' : 'border-gray-300'}
/>
{!isTogether && (
<div className="offline-notice">
<p>Join a session to enable real-time collaboration</p>
<button onClick={() => /* join session logic */ {}}>
Join Session
</button>
</div>
)}
</div>
)
}
Connection Status Dashboard
Build a comprehensive connection monitoring component:
import { useIsTogether, useConnectedUsers, useIsSynchronized } from 'react-together'
function SessionDashboard() {
const isTogether = useIsTogether()
const connectedUsers = useConnectedUsers()
const isSynchronized = useIsSynchronized()
if (!isTogether) {
return (
<div className="dashboard offline">
<h3>📶 Session Status</h3>
<div className="status-grid">
<div className="status-item">
<span className="label">Connection:</span>
<span className="value disconnected">Disconnected</span>
</div>
<div className="status-item">
<span className="label">Users:</span>
<span className="value">0</span>
</div>
<div className="status-item">
<span className="label">Sync Status:</span>
<span className="value">N/A</span>
</div>
</div>
<div className="actions">
<button className="connect-btn">
Connect to Session
</button>
</div>
</div>
)
}
return (
<div className="dashboard online">
<h3>📶 Session Status</h3>
<div className="status-grid">
<div className="status-item">
<span className="label">Connection:</span>
<span className="value connected">✓ Connected</span>
</div>
<div className="status-item">
<span className="label">Users:</span>
<span className="value">{connectedUsers.length}</span>
</div>
<div className="status-item">
<span className="label">Sync Status:</span>
<span className={`value ${isSynchronized ? 'synced' : 'syncing'}`}>
{isSynchronized ? '✓ Synchronized' : '⏳ Synchronizing...'}
</span>
</div>
</div>
<div className="user-list">
<h4>Connected Users:</h4>
<ul>
{connectedUsers.map(user => (
<li key={user.userId} className={user.isYou ? 'me' : ''}>
{user.nickname} {user.isYou && '(You)'}
</li>
))}
</ul>
</div>
</div>
)
}
Smart Feature Loading
Conditionally load collaborative features only when connected:
import { Suspense, lazy } from 'react'
import { useIsTogether } from 'react-together'
// Lazy load collaborative components
const CollaborativeCursors = lazy(() => import('./CollaborativeCursors'))
const SharedCanvas = lazy(() => import('./SharedCanvas'))
const UserAvatars = lazy(() => import('./UserAvatars'))
function SmartCollaborativeApp() {
const isTogether = useIsTogether()
return (
<div className="app">
<header>
<h1>My App</h1>
{isTogether && (
<Suspense fallback={<div>Loading collaboration features...</div>}>
<UserAvatars />
</Suspense>
)}
</header>
<main>
{isTogether ? (
<Suspense fallback={<div>Loading shared workspace...</div>}>
<SharedCanvas />
<CollaborativeCursors />
</Suspense>
) : (
<div className="solo-workspace">
<p>Working in solo mode</p>
<button onClick={() => /* create session */ {}}>
Start Collaborating
</button>
</div>
)}
</main>
</div>
)
}
Conditional Data Persistence
Handle data differently based on connection status:
import { useIsTogether, useStateTogether } from 'react-together'
import { useEffect, useState } from 'react'
function TodoApp() {
const isTogether = useIsTogether()
// Use shared state when connected, local state when offline
const [sharedTodos, setSharedTodos] = useStateTogether('todos', [])
const [localTodos, setLocalTodos] = useState([])
const todos = isTogether ? sharedTodos : localTodos
const setTodos = isTogether ? setSharedTodos : setLocalTodos
// Save to localStorage when offline
useEffect(() => {
if (!isTogether) {
localStorage.setItem('offline-todos', JSON.stringify(localTodos))
}
}, [localTodos, isTogether])
// Load from localStorage when going offline
useEffect(() => {
if (!isTogether) {
const saved = localStorage.getItem('offline-todos')
if (saved) {
setLocalTodos(JSON.parse(saved))
}
}
}, [isTogether])
const addTodo = (text: string) => {
const newTodo = {
id: Date.now().toString(),
text,
completed: false,
createdAt: new Date().toISOString()
}
setTodos([...todos, newTodo])
}
return (
<div className="todo-app">
<div className="header">
<h2>Todo List</h2>
<div className="mode-indicator">
{isTogether ? (
<span className="collaborative">
🤝 Collaborative Mode - {todos.length} shared todos
</span>
) : (
<span className="offline">
💾 Offline Mode - {todos.length} local todos
</span>
)}
</div>
</div>
<div className="todo-input">
<input
type="text"
placeholder={
isTogether
? "Add a shared todo..."
: "Add a local todo..."
}
onKeyPress={(e) => {
if (e.key === 'Enter' && e.currentTarget.value.trim()) {
addTodo(e.currentTarget.value.trim())
e.currentTarget.value = ''
}
}}
/>
</div>
<ul className="todo-list">
{todos.map(todo => (
<li key={todo.id} className={todo.completed ? 'completed' : ''}>
<input
type="checkbox"
checked={todo.completed}
onChange={(e) => {
const updated = todos.map(t =>
t.id === todo.id ? { ...t, completed: e.target.checked } : t
)
setTodos(updated)
}}
/>
<span>{todo.text}</span>
{!isTogether && (
<small className="offline-badge">Local</small>
)}
</li>
))}
</ul>
{!isTogether && todos.length > 0 && (
<div className="sync-prompt">
<p>You have {todos.length} local todos</p>
<button onClick={() => /* sync to session */ {}}>
Join Session to Share
</button>
</div>
)}
</div>
)
}
Progressive Enhancement Pattern
Enhance basic functionality with collaborative features:
import { useIsTogether, useConnectedUsers, useCursors } from 'react-together'
function ProgressiveCollaborativeForm() {
const isTogether = useIsTogether()
const connectedUsers = useConnectedUsers()
const cursors = useCursors()
return (
<div className="form-container" style={{ position: 'relative' }}>
<form className="contact-form">
<h2>Contact Form</h2>
{/* Basic form works offline */}
<div className="field">
<label htmlFor="name">Name</label>
<input
id="name"
type="text"
placeholder="Your name"
/>
</div>
<div className="field">
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
placeholder="[email protected]"
/>
</div>
<div className="field">
<label htmlFor="message">Message</label>
<textarea
id="message"
placeholder="Your message..."
rows={4}
/>
</div>
<button type="submit">
Send Message
</button>
</form>
{/* Enhanced with collaborative features when connected */}
{isTogether && (
<>
{/* Show live cursors */}
{Object.entries(cursors).map(([userId, position]) => (
<div
key={userId}
className="cursor"
style={{
position: 'absolute',
left: position.x,
top: position.y,
pointerEvents: 'none',
zIndex: 1000
}}
>
<div className="cursor-pointer">→</div>
<div className="cursor-label">
{connectedUsers.find(u => u.userId === userId)?.nickname}
</div>
</div>
))}
{/* Collaboration status */}
<div className="collaboration-status">
<p>
✨ Enhanced with real-time collaboration
</p>
<p>
{connectedUsers.length} user(s) can see your cursor movements
</p>
</div>
</>
)}
</div>
)
}
Best Practices
Connection State Management
import { useIsTogether } from 'react-together'
import { useEffect, useState } from 'react'
function useConnectionHistory() {
const isTogether = useIsTogether()
const [connectionHistory, setConnectionHistory] = useState<Array<{
timestamp: Date
status: 'connected' | 'disconnected'
}>>([])
useEffect(() => {
setConnectionHistory(prev => [
...prev,
{
timestamp: new Date(),
status: isTogether ? 'connected' : 'disconnected'
}
])
}, [isTogether])
return { isTogether, connectionHistory }
}
Graceful Degradation
import { useIsTogether } from 'react-together'
function useCollaborativeFeatures() {
const isTogether = useIsTogether()
return {
// Enable features based on connection
showCursors: isTogether,
enableRealTimeSync: isTogether,
showUserList: isTogether,
allowSessionSharing: isTogether,
// Provide fallbacks
saveStrategy: isTogether ? 'realtime' : 'localStorage',
notificationLevel: isTogether ? 'minimal' : 'verbose'
}
}
Common Patterns
- Feature Flags: Use as a feature flag for collaborative functionality
- Progressive Enhancement: Start with basic features, enhance when connected
- Conditional Rendering: Show different UI based on connection status
- Data Strategy: Switch between shared and local data based on connection
- Performance: Avoid loading collaborative features when not needed
TypeScript Support
useIsTogether
is fully typed and returns a boolean value:
import { useIsTogether } from 'react-together'
const isTogether: boolean = useIsTogether()
Technical Notes
useIsTogether
is an alias for useIsJoined
from @multisynq/react
. It returns true
when the user has successfully joined a session and the connection is active.
Connection status can change during the session due to network issues. Always handle both connected and disconnected states gracefully in your UI.
Responses are generated using AI and may contain mistakes.