Make your Slate editor collaborative in minutes

Liveblocks enables you to add realtime syncing and multiplayer features to your Slate editor with Yjs, a realtime data store designed for collaborative text editors.

Companies of all sizes and industries use Liveblocks

Multiplayer Editing -
Add realtime collaboration to your product experience

Let users co-edit text and manipulate data simultaneously, in realtime—just like Figma or Notion.

import LiveblocksProvider from "@liveblocks/yjs";import { useEffect, useMemo, useState } from "react";import { createEditor, Editor, Transforms } from "slate";import { Editable, Slate, withReact } from "slate-react";import { withYjs, YjsEditor } from "@slate-yjs/core";import * as Y from "yjs";import { useRoom } from "../liveblocks.config";import styles from "./CollaborativeEditor.module.css";
export function CollaborativeEditor() { const room = useRoom(); const [connected, setConnected] = useState(false); const [sharedType, setSharedType] = useState<Y.XmlText>(); const [provider, setProvider] = useState<LiveblocksProviderType>();
// Set up Liveblocks Yjs provider useEffect(() => { const yDoc = new Y.Doc(); const yProvider = new LiveblocksProvider(room, yDoc); const sharedDoc = yDoc.get("slate", Y.XmlText) as Y.XmlText; yProvider.on("sync", setConnected);
setSharedType(sharedDoc); setProvider(yProvider);
return () => { yDoc?.destroy(); yProvider?.off("sync", setConnected); yProvider?.destroy(); }; }, [room]);
if (!connected || !sharedType || !provider) { return <div>Loading…</div>; }
return <SlateEditor sharedType={sharedType} />;}
const emptyNode = { children: [{ text: "" }],};
function SlateEditor({ sharedType }: { sharedType: Y.XmlText }) { const editor = useMemo(() => { const e = withReact(withYjs(createEditor(), sharedType));
// Ensure editor always has at least 1 valid child const { normalizeNode } = e; e.normalizeNode = (entry) => { const [node] = entry;
if (!Editor.isEditor(node) || node.children.length > 0) { return normalizeNode(entry); }
Transforms.insertNodes(editor, emptyNode, { at: [0] }); };
return e; }, []);
useEffect(() => { YjsEditor.connect(editor); return () => YjsEditor.disconnect(editor); }, [editor]);
return ( <div className={styles.container}> <div className={styles.editorContainer}> <Slate editor={editor} initialValue={[emptyNode]}> <Editable className={styles.editor} placeholder="Start typing here…" /> </Slate> </div> </div> );}

Turn your product into the space where people and AI collaborate

We use cookies to collect data to improve your experience on our site. Read our Privacy Policy to learn more.