docs/solutions/logic-errors/2026-05-09-beforeinput-substitutions-must-flush-native-text-before-replacement.md
Browser text substitutions can send a native insertText beforeinput, mutate
the DOM, then send a model-owned replacement before the matching input event
imports the native text.
If Slate applies the replacement first, the native DOM text is lost or the replacement lands at the wrong current selection.
i + native S + replacement I rendered I
instead of IS.iSI.🙂 rendered 🙂 . instead of
🙂. .The runtime now treats native text beforeinput as pending model work until the
matching input event or the next model-owned beforeinput:
runtime-before-input-events.ts queues native text repair when Slate allows
native insertText.mutation-controller.ts applies provided replacement target ranges directly
instead of relying on the current selection.selection-reconciler.ts honors expanded insertText target ranges even
when model selection is preferred.Mac autocorrect and punctuation substitution are ordered around browser-owned DOM text. Slate must import the browser-owned text before applying the later model-owned replacement, but the replacement still has to use the event's target range rather than whatever selection the repair leaves behind.
Expanded insertText target ranges are replacement instructions. Collapsed
insertText ranges can still prefer the current model selection.
getTargetRanges()
and include both native DOM mutation and follow-up model-owned replacement.insertText target
range import, and replacement text using the provided selection.