Skip to content

Repository files navigation

@brainstorm-os/react-yjs

React hooks that bridge Yjs CRDT state into React.

Read a shared document's live state with useYMap / useYText / useYDoc and render presence with useAwareness — no hand-rolled observe/unobserve loops, no forceUpdate, no stale reads. Updates are batched per microtask and the hooks are read-only by contract, so your render path stays clean and your mutations stay explicit.

It's the reactivity layer behind Brainstorm, extracted to stand on its own.

License: MIT  peer deps: react · yjs  ·  zero runtime dependencies

npm install @brainstorm-os/react-yjs yjs react

Quick start

import * as Y from "yjs";
import { useYMap, useYText } from "@brainstorm-os/react-yjs";

const doc = new Y.Doc();
const meta = doc.getMap("meta");

function Title() {
  // Re-renders only when `meta` changes; returns a plain snapshot object.
  const { title } = useYMap(meta);
  return <h1>{title ?? "Untitled"}</h1>;
}

function Body({ text }: { text: Y.Text }) {
  const value = useYText(text); // live string
  return <p>{value}</p>;
}

Mutations flow through Yjs as usual (meta.set("title", "…")) — the hooks observe and re-render; they never write.

What's in the box

Value hooks — subscribe to a single shared type and get a snapshot back:

Hook Reads
useYMap(map) a Y.Map as a plain object
useYText(text) a Y.Text as a string
useYXmlFragment(frag) a Y.XmlFragment change signal
useYDoc(docOrId) a whole Y.Doc (+ useYDocLoaded / useYDocApplyPending)

Presence & awarenessuseAwareness for React, plus a framework-free core: createLocalAwareness, createSyncedAwareness, createPresenceTransport, and createLoopbackTransports for tests.

Document resolutionYDocProvider + createYDocResolver let a host map a stable entity id to a lazily-loaded, transport-synced Y.Doc, so components can call useYDoc(id) without knowing where the doc comes from.

Framework-free stores — every hook is a thin useSyncExternalStore wrapper over a pure store you can drive without React: createYStore, yMapStore, yTextStore, yDocStore, and the generic createQueryStore for async lists. Use these in vanilla-DOM views, workers, or tests.

Live entity listsuseLiveEntities binds any { list(), onChange? } source to React with debouncing and structural short-circuiting. useVaultEntities is the Brainstorm-flavored specialization; both expect a small host contract described in src/brainstorm-types.ts — provide any object matching those shapes to use them outside Brainstorm.

Peer dependencies

react (^19) and yjs (^13.6.30) are peer dependencies — the library brings no copy of its own. react is marked optional: the *Store builders and the awareness/presence core work in a non-React runtime.

Develop

bun install      # or npm install
bun run test     # vitest — 99 tests
bun run typecheck
bun run build    # tsup → dist/ (ESM + .d.ts)

License

MIT © Brainstorm OS. Part of the Brainstorm project.

About

React hooks that bridge Yjs CRDT state into React — value hooks, awareness/presence, and framework-free stores. Zero runtime deps.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages