Skip to content
T.P.

Projects Docs — Real-Time Collaborative Document Editor

Docs — Real-Time Collaborative Document Editor

Google Docs-style collaborative editor with rich text, live cursors, comments, workspaces, templates, and export — TipTap, Liveblocks, Convex, and Clerk.

Next.js · TipTap · Liveblocks · Convex · Clerk

GitHub Live Demo

Overview

Docs is a Google Docs-style collaborative editor supporting rich text formatting, tables, images, task lists, live cursors, threaded comments with @mentions, organization workspaces, templates, and export.

The build splits responsibility across four services:

Architecture diagram of Docs: TipTap, Liveblocks, Convex, and Clerk
Fig. 1. Architecture Diagram

The connecting design choice is that the Convex document ID doubles as the Liveblocks room ID — Convex never stores document content, only the pointer to where it lives.

Editor

The editor is TipTap (a ProseMirror wrapper) configured with extensions for underline, text color, highlighting, alignment, task lists, tables, and resizable images.

Two settings matter: history: false disables TipTap’s own undo stack so it doesn’t conflict with Liveblocks’ collaborative history, and immediatelyRender: false avoids a server/client hydration mismatch.

Font size and line height — missing from TipTap by default — were built as custom extensions: font size as a mark (inline, like bold) and line height as a node attribute (block-level, applied via nodesBetween/setNodeMarkup).

A Zustand store shares the live editor instance across the toolbar and menu bar so formatting buttons stay in sync with the cursor.

Multiplayer

Multiplayer runs through Liveblocks rooms, with Yjs (a CRDT) handling conflict-free merges underneath — no custom merge logic was written.

Presence features include an avatar stack and cursor colors generated by hashing each user’s name into an HSL hue, so collaborators get consistent colors without a database column. A draggable margin ruler stores its state in Liveblocks Storage rather than local state, so dragging a margin updates the page for every viewer in the room.

Comments anchor to selected text, rendering as margin threads on desktop and floating popovers on mobile via a CSS breakpoint; @mentions query an organization’s members through Clerk, and an inbox notification system resolves room IDs back to document titles via Convex.

Security

Security runs through a single auth handshake: before joining a room, the browser calls a Liveblocks-auth route that verifies the Clerk session, looks up the document in Convex by room ID, and checks that the user is either the owner or a member of the document’s organization before issuing a scoped, room-only Liveblocks token. The same ownership check is repeated server-side in Convex mutations, so client-side UI restrictions are never the only protection.

Auth handshake diagram for Docs Liveblocks room access
Fig. 2. Auth Handshake

Data and polish

Convex’s schema is a single documents table with indexes for owner and organization plus a full-text search index on title; one query branches on search term and organization context to serve four list variants.

Pagination loads five documents at a time, search state lives in the URL, and title edits are debounced. Seven templates are stored as HTML strings loaded into a fresh document on creation. Export covers JSON, HTML, plain text, and PDF (via the browser’s print dialog, using print-specific CSS to hide the toolbar).

Known gaps

Uploaded images use temporary local blob URLs rather than persistent storage, and access control is currently binary (owner or organization member) with no granular sharing roles.

Next: Cine — YouTube-Style Video Platform