RealtimeChat
A realtime chat component with live message updates and connection status.
Props
Unique identifier for the chat room
Display name for the current user
Additional CSS classes to apply to the component
Hook: useRealtimeChat
The component uses the useRealtimeChat hook for managing chat state.
Hook Props
Unique identifier for the chat room
Display name for the current user
Hook Return Values
Array of chat messages in the room
sendMessage
(content: string) => Promise<void>
Function to send a new message
Connection status to the realtime backend
Types
interface UseRealtimeChatProps {
roomName: string;
username: string;
}
interface ChatMessage {
id: string;
content: string;
user: {
name: string;
};
createdAt: string;
}
Example
import { RealtimeChat } from "@/components/realtime-chat";
export default function ChatRoom() {
return (
<RealtimeChat
roomName="general"
username="John Doe"
className="h-[600px]"
/>
);
}
Direct Hook Usage
import { useRealtimeChat } from "@/hooks/use-realtime-chat";
export default function CustomChat() {
const { messages, sendMessage, isConnected } = useRealtimeChat({
roomName: "general",
username: "John Doe",
});
return (
<div>
<div>Connected: {isConnected ? "Yes" : "No"}</div>
{messages.map((msg) => (
<div key={msg.id}>
{msg.user.name}: {msg.content}
</div>
))}
<button onClick={() => sendMessage("Hello!")}>
Send
</button>
</div>
);
}
RealtimeCursors
A component for displaying realtime cursor positions of multiple users.
Props
Unique identifier for the cursor room
Display name for the current user’s cursor
Color for the current user’s cursor (hex color)
Content to render inside the cursor tracking area
Additional CSS classes to apply to the component
Hook: useRealtimeCursors
The component uses the useRealtimeCursors hook for managing cursor state.
Hook Props
Unique identifier for the cursor room
Display name for the current user’s cursor
Color for the current user’s cursor (hex color)
Throttle interval in milliseconds for cursor position updates
Hook Return Values
Array of other users’ cursor positions (excludes current user)
updateCursor
(position: CursorPosition) => void
Function to update the current user’s cursor position
createMouseMoveHandler
(container: HTMLElement) => (e: MouseEvent) => void
Creates a mouse move event handler that calculates container-relative positions
setContainer
(container: HTMLElement | null) => void
Sets the container reference for coordinate calculations
Connection status to the realtime backend
Unique session identifier for the current user
Types
interface CursorPosition {
x: number;
y: number;
}
interface Cursor {
id: string;
name: string;
color: string;
position: CursorPosition;
}
interface CursorData {
position: CursorPosition;
name: string;
color: string;
}
interface UseRealtimeCursorsProps {
roomName: string;
username: string;
userColor?: string;
throttleMs?: number;
}
Example
import { RealtimeCursors } from "@/components/realtime-cursors";
export default function CollaborativeCanvas() {
return (
<RealtimeCursors
roomName="canvas-room"
username="John Doe"
userColor="#ff6b6b"
className="w-full h-screen"
>
<div>Your canvas content here</div>
</RealtimeCursors>
);
}
Direct Hook Usage
import { useRealtimeCursors } from "@/hooks/use-realtime-cursors";
import { useEffect, useRef } from "react";
export default function CustomCursors() {
const containerRef = useRef<HTMLDivElement>(null);
const { cursors, createMouseMoveHandler, setContainer, isConnected } =
useRealtimeCursors({
roomName: "canvas-room",
username: "John Doe",
userColor: "#ff6b6b",
throttleMs: 50,
});
useEffect(() => {
const container = containerRef.current;
if (!container) return;
setContainer(container);
const handleMove = createMouseMoveHandler(container);
container.addEventListener("mousemove", handleMove);
return () => {
container.removeEventListener("mousemove", handleMove);
setContainer(null);
};
}, [createMouseMoveHandler, setContainer]);
return (
<div ref={containerRef}>
{cursors.map((cursor) => (
<div
key={cursor.id}
style={{
position: "absolute",
left: cursor.position.x,
top: cursor.position.y,
color: cursor.color,
}}
>
{cursor.name}
</div>
))}
</div>
);
}
RealtimeAvatarStack
A component that displays avatars of users currently present in a room.
Props
Unique identifier for the presence room
Current user information
URL to user’s avatar image
Fallback color for avatar (hex color)
Maximum number of avatars to display before showing count
size
'sm' | 'md' | 'lg'
default:"md"
Size of the avatar stack
Additional CSS classes to apply to the component
Hook: useRealtimePresenceRoom
The component uses the useRealtimePresenceRoom hook for managing presence state.
Hook Props
Unique identifier for the presence room
Interval in milliseconds for sending presence heartbeats
Hook Return Values
Array of users currently present in the room
Connection status to the realtime backend
Total number of users in the room
Types
interface UserPresence {
name: string;
image?: string;
color?: string;
}
interface PresenceUser {
id: string;
name: string;
image?: string;
color?: string;
}
interface UseRealtimePresenceRoomProps {
roomName: string;
user: UserPresence;
heartbeatMs?: number;
}
Example
import { RealtimeAvatarStack } from "@/components/realtime-avatar-stack";
export default function DocumentHeader() {
return (
<RealtimeAvatarStack
roomName="document-123"
user={{
name: "John Doe",
image: "https://example.com/avatar.jpg",
color: "#3b82f6",
}}
maxVisible={3}
size="sm"
/>
);
}
Direct Hook Usage
import { useRealtimePresenceRoom } from "@/hooks/use-realtime-presence-room";
export default function CustomPresence() {
const { users, isConnected, userCount } = useRealtimePresenceRoom({
roomName: "document-123",
user: {
name: "John Doe",
image: "https://example.com/avatar.jpg",
color: "#3b82f6",
},
heartbeatMs: 5000,
});
return (
<div>
<div>Connected: {isConnected ? "Yes" : "No"}</div>
<div>Users online: {userCount}</div>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
Notes
- The component automatically joins the room on mount and leaves on unmount
- Presence heartbeats are sent periodically to maintain user presence
- Session IDs are generated uniquely per component instance to avoid conflicts in iframes/tabs