docs/solutions/ui-bugs/2026-04-25-slate-react-repair-induced-selectionchange-must-stay-model-owned.md
After Slate handles a destructive browser edit as model-owned, the DOM repair
it schedules can itself trigger selectionchange. If that repair-induced
selectionchange re-enters the pipeline as dom-current, a delayed browser
selection can reopen DOM authority after the model mutation is already correct.
Alt+Backspace in /examples/richtext could produce screenshot-class
drift where visual text/caret state no longer matched the intended model lane.selectionchange
events reported selectionSource: dom-current.selectionchange imports while model selection was
preferred was too blunt. It fixed the word-delete row but broke legitimate
DOM selection import for toolbar commands and paste.Treat destructive model-owned beforeinput repairs as model-owned all the way
through the repair-induced selectionchange event:
repair: {
focus: true,
kind: 'repair-caret',
selectionSourceTransition: {
preferModelSelection: true,
reason: 'model-command',
selectionSource: 'model-owned',
},
}
Then, when selectionchange is known to be repair-induced, canonicalize the
editable selection preference before tracing or importing:
if (selectionChangeOrigin === 'repair-induced') {
setEditableModelSelectionPreference({
preferModelSelection: true,
selectionSource: 'model-owned',
})
}
Finally, clear only the transient repair origin after that repair event. Keep model preference/source active, but allow later explicit user DOM selection to import normally.
The repair event is not a fresh user intent. It is a consequence of a
model-owned mutation. Letting it report as dom-current creates two competing
selection authorities inside one native action.
The narrow rule keeps the right split:
selectionchange stays model-ownedselectionchange separately from native user
selectionchange.