docs/plans/2026-04-06-slate-v2-react-19-2-convergence.md
Supporting plan. For current queue and roadmap truth, see master-roadmap.md.
slate-react to React 19.2+, and the replacement-candidate
repo must match that honestly.useSyncExternalStore subscriptions and no effect-mirrored
editor state.<Activity> proof lane, and a very
selective useEffectEvent pass.Pros:
<Activity> proof lane be real instead of theoreticalCons:
slate-reactslate-reactPros:
Cons:
<Activity> or useEffectEvent proof half-fakePros:
Cons:
Activity / useEffectEvent posture unprovedChoose Option A, but stage it like C first.
That means:
<Activity> proof laneuseEffectEvent lands only where it removes real effect-owned callback
churnstartTransition / useDeferredValue do not land unless one derived
non-urgent UI lane actually earns themreact, react-dom, @types/react, and @types/react-dom to 19.2.x
where the repo-wide toolchain requires them.slate-react, tests, and
site examples green.<Activity> proof lane in slate-react.slate-react effects and use useEffectEvent only where
there is a real effect-owned callback seam.startTransition / useDeferredValue out of editor correctness paths.docs/slate-v2/* to the latest proved state.<Activity>slate-react to ActivityuseEffectEvent adoption just to say we used it<Activity> as the default editor boundary<Activity> to hide rerender or selection bugsstartTransitionuseDeferredValue for active selection or text correctnessuseEffectEvent unless it
removes real dependency-array or rebinding painuseEffectEvent CallCurrent read:
Why:
Editable effects are mostly external DOM synchronization and are
already shaped reasonablyuseEffectEventAllowed now:
Editable only if it clearly simplifies DOM listener wiring
without changing semanticsNot required now:
useEffectEvent<Activity> Proof ShapeAdd one optional proof lane, not a default runtime path.
Target proof:
<Activity mode=\"hidden\">Best lane:
slate-react runtime test firstslate-browser or Playwright example lane only if runtime
proof alone is not enoughAnswer:
You can stage the implementation, but you should not claim React 19.2 convergence while the repo root still installs React 18.2.
slate-react<Activity> proof lane in
runtime.tsx
is green and proves hidden/resume
correctness.useEffectEvent usage is local to effect-owned callback wiring and does
not leak into public runtime APIs.startTransition / useDeferredValue usage is introduced for editor
correctness.yarn installyarn build:slate-browser:playwrightyarn tsc:examplesyarn lint:typescript only if the root React upgrade or site fallout makes
the package-level checks insufficientyarn workspace slate-react run test<Activity mode="hidden">
must:
yarn test:slate-browser:ime:local because Editable effect wiring changedslate-react or site build drift.<Activity> reveals stale DOM bridge assumptions that normal mount/unmount
never exercised.useEffectEvent adoption makes the code worse, not better.<Activity> hide/resume correctness with these exact
observables:
useEffectEvent candidate. If none earns it, leave it out of
tranche 1.startTransition or useDeferredValue in tranche 1 unless a
derived pane or overlay lane already exists and is measurably expensive.Completed on the renamed replacement-candidate graph in
/Users/zbeyens/git/slate-v2.
What landed:
react, react-dom, @types/react, and @types/react-dom on 19.2next on latest 16.2.2slate-react public peer surface aligned to >=19.2.0useEffectEvent cut in
editable.tsx<Activity> proof lane in
runtime.tsxVerification run:
yarn installyarn tsc:examplesyarn build:slate-browser:playwrightyarn workspace slate-react run testyarn build:nextyarn test:slate-browser:ime:local