docs/solutions/performance-issues/2026-05-12-slate-render-props-should-not-carry-moving-paths.md
Slate paths are current tree addresses, not stable node identity. Passing them through default React render props turns every structural shift into either a wide rerender requirement or a stale handler bug.
RenderElementProps exposed eager path and index.RenderVoidProps exposed eager path.DOMEditor.findPath still had a weak-map fallback path that could be stale
after skipped structural rerenders.path and rerendering shifted siblings. That preserves
correctness by giving up the rerender-breadth win.path and skipping shifted siblings. That preserves React
performance by making closed-over event handlers unsafe.data-slate-path as app truth. DOM metadata is useful fallback and
debug state, but it should not define the public render contract.Cut eager moving addresses from public render props:
type RenderElementProps<TElement extends Element = Element> = {
attributes: RenderElementAttributes
children: ReactNode
element: TElement
isInline: boolean
slots: EditableElementSlots
}
type RenderVoidProps<TElement extends Element = Element> = {
element: TElement
}
Resolve current paths lazily where the app actually needs them:
const path = ReactEditor.findPath(editor, element)
const path = useElementPath()
Back findPath with runtime ids before weak-map indexes:
const runtimeId = NODE_TO_RUNTIME_ID.get(node)
if (runtimeId) {
const path = Editor.getPathByRuntimeId(editor, runtimeId)
if (path) return path
}
Move examples to event-time path resolution inside handlers instead of closing over render-time path props.
Runtime id is stable identity; path is a query against the current tree. Once the public API follows that split, structural root-order changes can stay cheap: mounted siblings keep their identity without being rerendered just to refresh a moving address.
The lazy APIs preserve Slate-close DX. App code still calls
ReactEditor.findPath(editor, element) when it wants to mutate the current
element. Render-time path display remains possible through useElementPath(),
but that opt-in hook owns the rerender cost explicitly.
DOMEditor.findPath should prefer live runtime-id lookup before weak-map or
DOM metadata fallbacks.path or index returns to
default render props.