docs/solutions/logic-errors/2026-05-07-slate-v2-empty-inline-backspace-must-path-delete-the-inline.md
The inlines example reproduced #5972: after clearing the editable inline text, pressing Backspace deleted the character before the inline instead of deleting the empty inline itself.
an! instead of an !.an, the
empty inline stayed present, and the following text stayed separate.[0,3,0]@0 in the empty inline.1; Slate selection still maps to
offset 0.Classify Backspace at the start of an empty editable inline before resolving the normal character target. In that case, the delete target is the inline element path, not a text range into the previous leaf.
const emptyInlinePath =
reverse && unit === 'character' && distance === 1
? getEmptyEditableInlinePathAtPoint(editor, at)
: null
if (emptyInlinePath) {
return {
kind: 'path',
path: emptyInlinePath,
fallbackPoint:
EditorApi.before(editor, emptyInlinePath, { voids: true }) ??
EditorApi.after(editor, emptyInlinePath, { voids: true }),
initialAt,
}
}
The classifier must reject void and read-only inline nodes:
NodeApi.isElement(parent) &&
getEditorSchema(editor).isInline(parent) &&
!getEditorSchema(editor).isVoid(parent) &&
!getEditorSchema(editor).isReadOnly(parent) &&
NodeApi.string(parent) === ''
Lock it with both proof layers:
bun test ./packages/slate/test/delete-contract.ts --test-name-pattern "empty editable inline"
PLAYWRIGHT_RETRIES=0 bunx playwright test playwright/integration/examples/inlines.test.ts --project=chromium --grep "empty editable inline"
Collapsed character Backspace normally asks Editor.before(..., unit: 'character') for the target. At the start of an empty inline, that target is
the preceding text character, so the planner deletes real content.
An empty editable inline is different. There is no inline text character to delete. The user intent is structural: remove the empty inline and place the caret at the adjacent valid point. Path delete gives core deletion the right operation shape, lets adjacent text merge normally, and keeps React/browser repair on the model-owned path.
1 can still be Slate offset 0.