docs/solutions/ui-bugs/2026-05-07-slate-react-chrome-composition-fallback-must-cancel-model-owned-overlap.md
すし` after a model-owned replacement should have won.
Chrome's compositionend fallback wrote committed IME text even after a model-owned command had already replaced the active composition range. The user would see stale composition text appended after the model command's result.
---.---すし.event.data from compositionend after the
model-owned replacement had superseded the composition.selectionSource === 'composition-owned'
broke decorated spanning composition by producing albeta instead of
alすしbeta.compositionend payload as commit-worthy. That duplicates
composition text after model-owned overlap.composition-owned selection source as canceled. Real DOM
composition can temporarily report dom-current, and still must commit.Thread the input controller into composition-end handling and let the Chrome fallback skip model insertion only when the active composition was superseded by a model-owned command.
const shouldCommitChromeFallback =
ReactEditor.isComposing(editor) &&
inputController.state.selectionSource !== 'model-owned'
commitChromeCompositionEndFallback({
editor,
rootElement: event.currentTarget,
shouldCommit: shouldCommitChromeFallback,
text: event.data,
})
When shouldCommit is false, still remove unmanaged composition DOM text. That
keeps stale browser-owned text out of the rendered editor without writing it
back into the Slate model.
During normal DOM composition, selection ownership can shift as the browser moves the DOM caret. That alone is not cancellation. A model-owned command is a stronger signal: Slate has deliberately moved or replaced the model selection, so Chrome's later fallback payload is stale for that range.
The narrow guard keeps legitimate DOM-current composition commits alive while dropping the stale payload after model-owned overlap.