Overview
The Cursors
component displays the real-time mouse cursors of all connected users on the page. It provides smooth cursor tracking with customizable colors, animations, and user information display. This component is perfect for collaborative applications where visual awareness of other users’ activity is important.
Perfect for: Collaborative design tools, document editors, drawing applications, presentations, and any interface where cursor awareness enhances collaboration.
Basic Usage
import { Cursors } from 'react-together'
function CollaborativeCanvas() {
return (
<div className="app">
{/* Your app content */}
<div className="canvas-area">
<p>Move your mouse around to see cursors!</p>
</div>
{/* Cursors overlay */}
<Cursors />
</div>
)
}
Props
The Cursors
component accepts all props from both useCursors
options and cursor appearance options:
Cursor Tracking Options
Whether to hide your own cursor from the display
Whether to remove cursors when users leave the session
Milliseconds to throttle cursor position updates (16ms = ~60fps)
Cursor Appearance Options
Duration in milliseconds for cursor movement animations
getUserColor
(userId: string) => string
Function to determine cursor color for each user
Custom components to override cursor display
CursorsComponents Interface
interface CursorsComponents {
UserCursor?: React.ComponentType<UserCursorProps>
}
interface UserCursorProps {
userId: string
pageX: number
pageY: number
transitionDuration?: number
getUserColor?: (userId: string) => string
}
Examples
Basic Cursor Display
Simple cursor tracking with default settings:
import { Cursors } from 'react-together'
function BasicCursorDemo() {
return (
<div className="demo-container">
<h1>Collaborative Workspace</h1>
<div className="workspace">
<p>Move your mouse around this area!</p>
<div className="drawing-area">
<p>✏️ Drawing canvas simulation</p>
</div>
</div>
{/* Display all user cursors */}
<Cursors />
</div>
)
}
Custom Cursor Colors
Implement custom color assignment for different users:
import { Cursors } from 'react-together'
function ColorfulCursors() {
// Define a set of distinct colors for users
const getUserColor = (userId: string): string => {
const colors = [
'#FF6B6B', // Red
'#4ECDC4', // Teal
'#45B7D1', // Blue
'#96CEB4', // Green
'#FFEAA7', // Yellow
'#DDA0DD', // Plum
'#98D8C8', // Mint
'#F7DC6F' // Light Yellow
]
// Use user ID to consistently assign colors
const colorIndex = userId.split('').reduce((acc, char) =>
acc + char.charCodeAt(0), 0
) % colors.length
return colors[colorIndex]
}
return (
<div className="colorful-demo">
<h2>🎨 Colorful Cursors Demo</h2>
<div className="demo-area">
<p>Each user gets a unique color!</p>
<div className="color-palette">
{['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4'].map(color => (
<div
key={color}
className="color-swatch"
style={{ backgroundColor: color }}
/>
))}
</div>
</div>
<Cursors
getUserColor={getUserColor}
transitionDuration={150}
/>
</div>
)
}
Optimized settings for applications with many users:
import { Cursors } from 'react-together'
function HighPerformanceCursors() {
return (
<div className="performance-demo">
<h2>⚡ High Performance Cursors</h2>
<div className="demo-content">
<p>Optimized for many simultaneous users</p>
<div className="performance-metrics">
<div className="metric">
<label>Update Rate:</label>
<span>30 FPS</span>
</div>
<div className="metric">
<label>Animation:</label>
<span>Smooth</span>
</div>
</div>
</div>
<Cursors
throttleDelay={33} // 30 FPS instead of 60
transitionDuration={50} // Faster animations
deleteOnLeave={true} // Clean up immediately
/>
</div>
)
}
Custom Cursor Component
Create a custom cursor with user information display:
import { Cursors, useConnectedUsers } from 'react-together'
interface CustomCursorProps {
userId: string
pageX: number
pageY: number
transitionDuration?: number
getUserColor?: (userId: string) => string
}
function CustomUserCursor({
userId,
pageX,
pageY,
transitionDuration = 100,
getUserColor
}: CustomCursorProps) {
const connectedUsers = useConnectedUsers()
const user = connectedUsers.find(u => u.userId === userId)
const color = getUserColor ? getUserColor(userId) : '#3B82F6'
return (
<div
className="custom-cursor"
style={{
position: 'fixed',
left: pageX,
top: pageY,
pointerEvents: 'none',
zIndex: 9999,
transition: `all ${transitionDuration}ms ease-out`,
transform: 'translate(-2px, -2px)'
}}
>
{/* Cursor pointer */}
<div
className="cursor-pointer"
style={{
width: '20px',
height: '20px',
backgroundColor: color,
borderRadius: '50% 0 50% 50%',
transform: 'rotate(-45deg)',
position: 'relative'
}}
/>
{/* User info tooltip */}
<div
className="cursor-tooltip"
style={{
position: 'absolute',
top: '25px',
left: '10px',
backgroundColor: color,
color: 'white',
padding: '4px 8px',
borderRadius: '4px',
fontSize: '12px',
fontWeight: 'bold',
whiteSpace: 'nowrap',
boxShadow: '0 2px 4px rgba(0,0,0,0.2)'
}}
>
{user?.nickname || `User ${userId.slice(0, 8)}`}
</div>
</div>
)
}
function CustomCursorDemo() {
const getUserColor = (userId: string) => {
// Generate consistent color based on user ID
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7']
const index = userId.split('').reduce((acc, char) =>
acc + char.charCodeAt(0), 0
) % colors.length
return colors[index]
}
return (
<div className="custom-cursor-demo">
<h2>🎯 Custom Cursors with User Info</h2>
<div className="demo-area">
<p>Hover around to see custom cursors with user names!</p>
<div className="interactive-elements">
<button className="demo-button">Button 1</button>
<button className="demo-button">Button 2</button>
<input placeholder="Type here..." />
</div>
</div>
<Cursors
components={{
UserCursor: CustomUserCursor
}}
getUserColor={getUserColor}
transitionDuration={200}
/>
</div>
)
}
Drawing Application with Cursors
Integrate cursors into a collaborative drawing application:
import { Cursors, useStateTogether } from 'react-together'
import { useState, useRef } from 'react'
function CollaborativeDrawing() {
const [isDrawing, setIsDrawing] = useState(false)
const [currentPath, setCurrentPath] = useStateTogether<string[]>('drawing-paths', [])
const canvasRef = useRef<HTMLDivElement>(null)
const startDrawing = (e: React.MouseEvent) => {
setIsDrawing(true)
const rect = canvasRef.current?.getBoundingClientRect()
if (rect) {
const x = e.clientX - rect.left
const y = e.clientY - rect.top
setCurrentPath(prev => [...prev, `M ${x} ${y}`])
}
}
const draw = (e: React.MouseEvent) => {
if (!isDrawing) return
const rect = canvasRef.current?.getBoundingClientRect()
if (rect) {
const x = e.clientX - rect.left
const y = e.clientY - rect.top
setCurrentPath(prev => [...prev, `L ${x} ${y}`])
}
}
const stopDrawing = () => {
if (isDrawing && currentPath.length > 1) {
setCurrentPath(prev => [...prev, currentPath.join(' ')])
}
setIsDrawing(false)
}
return (
<div className="drawing-app">
<h2>🎨 Collaborative Drawing</h2>
<div className="drawing-controls">
<p>Draw with your mouse and see others' cursors!</p>
<button onClick={() => setCurrentPath([])}>
Clear Canvas
</button>
</div>
<div
ref={canvasRef}
className="drawing-canvas"
onMouseDown={startDrawing}
onMouseMove={draw}
onMouseUp={stopDrawing}
onMouseLeave={stopDrawing}
style={{
width: '800px',
height: '600px',
border: '2px solid #ccc',
borderRadius: '8px',
backgroundColor: 'white',
position: 'relative',
cursor: 'crosshair'
}}
>
{/* SVG for drawing paths */}
<svg
width="100%"
height="100%"
style={{ position: 'absolute', top: 0, left: 0 }}
>
{/* Render saved paths */}
{currentPath.map((path, index) => (
<path
key={index}
d={path}
stroke="#333"
strokeWidth="2"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
/>
))}
</svg>
</div>
{/* Display cursors over the drawing area */}
<Cursors
throttleDelay={8} // Very responsive for drawing
transitionDuration={50}
/>
</div>
)
}
Presentation Mode with Cursors
Use cursors for interactive presentations:
import { Cursors, useStateTogether } from 'react-together'
function InteractivePresentation() {
const [currentSlide, setCurrentSlide] = useStateTogether('slide', 0)
const slides = [
{
title: "Welcome to Interactive Presentations",
content: "See everyone's cursors in real-time!"
},
{
title: "Collaborative Features",
content: "Point and click to highlight content"
},
{
title: "Team Engagement",
content: "Everyone can participate visually"
}
]
return (
<div className="presentation-app">
<div className="presentation-controls">
<button
onClick={() => setCurrentSlide(Math.max(0, currentSlide - 1))}
disabled={currentSlide === 0}
>
← Previous
</button>
<span className="slide-counter">
{currentSlide + 1} / {slides.length}
</span>
<button
onClick={() => setCurrentSlide(Math.min(slides.length - 1, currentSlide + 1))}
disabled={currentSlide === slides.length - 1}
>
Next →
</button>
</div>
<div className="presentation-slide">
<h1>{slides[currentSlide].title}</h1>
<div className="slide-content">
<p>{slides[currentSlide].content}</p>
<div className="interactive-elements">
<div className="highlight-box">
<p>👆 Point at important content</p>
</div>
<div className="demo-chart">
<div className="chart-bar" style={{ height: '60px', backgroundColor: '#4ECDC4' }} />
<div className="chart-bar" style={{ height: '80px', backgroundColor: '#45B7D1' }} />
<div className="chart-bar" style={{ height: '40px', backgroundColor: '#96CEB4' }} />
</div>
</div>
</div>
</div>
<Cursors
transitionDuration={200}
throttleDelay={16}
/>
</div>
)
}
Gaming Interface with Cursors
Implement cursors in a collaborative gaming interface:
import { Cursors, useStateTogether, useConnectedUsers } from 'react-together'
function CollaborativeGame() {
const [gameState, setGameState] = useStateTogether('game', {
players: [] as Array<{id: string, score: number}>,
gameActive: false
})
const connectedUsers = useConnectedUsers()
const getUserColor = (userId: string) => {
const gamePlayer = gameState.players.find(p => p.id === userId)
if (gamePlayer) {
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']
const index = gameState.players.indexOf(gamePlayer)
return colors[index % colors.length]
}
return '#999'
}
return (
<div className="gaming-interface">
<div className="game-header">
<h2>🎮 Collaborative Game</h2>
<div className="player-stats">
<h3>Players ({connectedUsers.length})</h3>
{connectedUsers.map(user => (
<div key={user.userId} className="player-info">
<span
className="player-color"
style={{ backgroundColor: getUserColor(user.userId) }}
/>
<span className="player-name">{user.nickname}</span>
<span className="player-score">
Score: {gameState.players.find(p => p.id === user.userId)?.score || 0}
</span>
</div>
))}
</div>
</div>
<div className="game-area">
<div className="game-board">
<p>🎯 Click anywhere to play!</p>
<div className="game-grid">
{Array.from({ length: 16 }).map((_, i) => (
<div
key={i}
className="game-tile"
onClick={() => {
// Simulate game interaction
console.log(`Tile ${i} clicked`)
}}
/>
))}
</div>
</div>
</div>
<Cursors
getUserColor={getUserColor}
transitionDuration={100}
throttleDelay={16}
/>
</div>
)
}
Hide Own Cursor
Display only other users’ cursors:
import { Cursors } from 'react-together'
function OthersCursorsOnly() {
return (
<div className="others-cursors-demo">
<h2>👥 Others' Cursors Only</h2>
<p>You won't see your own cursor, only other users'</p>
<div className="demo-content">
<p>This is useful when you want to focus on other users' activity</p>
<div className="content-area">
<button>Interactive Element 1</button>
<button>Interactive Element 2</button>
<input placeholder="Type here..." />
</div>
</div>
<Cursors
omitMyValue={true}
transitionDuration={150}
/>
</div>
)
}
Throttling
Adjust throttleDelay
based on your needs:
// High precision (60 FPS) - good for drawing apps
<Cursors throttleDelay={16} />
// Balanced (30 FPS) - good for most applications
<Cursors throttleDelay={33} />
// Low bandwidth (15 FPS) - good for slow connections
<Cursors throttleDelay={66} />
Control animation smoothness:
// Smooth animations
<Cursors transitionDuration={200} />
// Responsive animations
<Cursors transitionDuration={50} />
// No animations (best performance)
<Cursors transitionDuration={0} />
Styling
The Cursors component uses these default styles:
/* Container for all cursors */
.cursors-container {
position: relative;
pointer-events: none;
}
/* Individual cursor styles */
.cursor-element {
position: fixed;
z-index: 9999;
pointer-events: none;
}
Best Practices
// ✅ Good - Reasonable throttling
<Cursors throttleDelay={16} />
// ❌ Bad - Too frequent updates
<Cursors throttleDelay={1} />
User Experience
// ✅ Good - Smooth animations
<Cursors transitionDuration={100} />
// ✅ Good - Custom colors for identification
<Cursors getUserColor={getUserColor} />
// ✅ Good - Clean up on leave
<Cursors deleteOnLeave={true} />
Mobile Considerations
// For mobile devices, consider disabling or adjusting
const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
function ResponsiveCursors() {
if (isMobile) {
return null // Mobile devices don't have traditional cursors
}
return <Cursors />
}
Common Patterns
- Design Tools: High-frequency updates for precise collaboration
- Document Editing: Medium-frequency updates with user identification
- Gaming: Color-coded cursors representing players
- Presentations: Smooth cursor animations for pointing
- Drawing Apps: Ultra-responsive cursor tracking
TypeScript Support
The Cursors component is fully typed:
import { Cursors, CursorsProps, UserCursorProps } from 'react-together'
const cursorsProps: CursorsProps = {
throttleDelay: 16,
transitionDuration: 100,
omitMyValue: false,
getUserColor: (userId: string) => '#3B82F6'
}
Responses are generated using AI and may contain mistakes.