apps/ui-library/content/docs/nextjs/realtime-monaco.mdx
<BlockItem name="realtime-monaco-nextjs" description="Real-time Monaco editor for collaborative applications." />
The Realtime Monaco component provides a collaborative code editor powered by Monaco and Yjs. It uses @supabase-labs/y-supabase under the hood to sync document state across clients through Supabase Realtime.
Features
The component creates a Yjs document and connects it to a Supabase Realtime channel using SupabaseProvider from @supabase-labs/y-supabase. A MonacoBinding from y-monaco bridges the Yjs document with the Monaco editor model, keeping them in sync.
When awareness is enabled, each user's cursor position and selection are broadcast to other clients in the same channel. Remote cursors are rendered with unique colors via dynamically injected CSS.
When persistence is enabled, the full Yjs document state is saved to a Postgres table so it can be restored when clients reconnect.
import { RealtimeMonaco } from '@/components/realtime-monaco'
export default function MonacoPage() {
return <RealtimeMonaco channel="realtime-monaco-demo" language="typescript" />
}
Enable persistence to save the editor content to your Supabase database. This requires a table to store the Yjs document state.
First, create the required table in your Supabase project:
create table yjs_documents (
room text primary key,
state text not null
);
Then pass persistence to the component:
import { RealtimeMonaco } from '@/components/realtime-monaco'
export default function MonacoPage() {
return <RealtimeMonaco channel="realtime-monaco-demo" language="typescript" persistence />
}
You can also pass a SupabasePersistenceOptions object:
<RealtimeMonaco
channel="realtime-monaco-demo"
language="typescript"
persistence={{
table: 'yjs_documents',
roomColumn: 'room',
stateColumn: 'state',
storeTimeout: 2000,
}}
/>
By default, cursor and selection positions are shared between collaborators. To disable this:
<RealtimeMonaco channel="realtime-monaco-demo" awareness={false} />
| Prop | Type | Description |
|---|---|---|
channel | string | Unique channel name used to sync editor content between collaborators in the same session. |
language? | string | Monaco language identifier (e.g. typescript, python). Defaults to javascript. |
height? | string | number | Height of the editor container. Accepts a pixel number or CSS string (e.g. "100%"). Defaults to 550. |
className? | string | CSS class applied to the editor wrapper element. |
awareness? | boolean | Awareness | Enables cursor and selection sharing between users. Pass false to disable or a custom Awareness instance. Defaults to true. |
persistence? | boolean | SupabasePersistenceOptions | Persists editor content to Supabase so it survives page reloads. Pass true for defaults or an options object for fine-grained control. |
theme? | 'light' | 'dark' | Color theme for the editor. Maps to Monaco's light and vs-dark themes. |
| Option | Type | Default | Description |
|---|---|---|---|
table | string | 'yjs_documents' | Name of the Postgres table used to store documents. |
schema | string | 'public' | Schema where the table is located. |
roomColumn | string | 'room' | Column used as the document identifier. |
stateColumn | string | 'state' | Column used to store the binary Yjs state. |
storeTimeout | number | 1000 | Debounce delay (ms) before persisting changes. |