docs/solutions/logic-errors/2026-05-06-slate-react-triple-click-delete-needs-full-block-selection-intent.md
Browser triple-click can produce a full-block or hanging full-block selection.
If Slate React collapses that into a generic delete-fragment command without
carrying the imported selection, Backspace can empty the block instead of
removing it.
/examples/richtext, triple-click the first paragraph and press
Backspace.slate-react can exercise stale
package dist output, so source changes appear ineffective.Carry the expanded selection on delete-fragment commands and let the mutation
controller recognize full-block browser ranges before falling back to normal
fragment deletion.
type EditableCommand =
| {
kind: 'delete-fragment'
direction?: 'backward' | 'forward'
selection?: Range | null
}
The command handler checks whether the range starts at a block start and ends at either that same block end or the next block start. That second shape is the browser hanging range produced by triple-click.
if (applyFullBlockDeleteFragment(editor, command.selection)) {
return true
}
editor.update((tx) => {
tx.fragment.delete(
command.direction ? { direction: command.direction } : undefined
)
})
Lock it with browser proof, not only model tests:
bun --filter slate-react build
PLAYWRIGHT_RETRIES=0 bunx playwright test \
playwright/integration/examples/richtext.test.ts \
--project=chromium \
--grep "selects the current block on browser triple click|removes the current block after browser triple click and Backspace"
The destructive edit command now preserves the selection that justified the command. The mutation layer can distinguish a browser full-block selection from ordinary selected text and remove the selected block instead of deleting its contents.
This keeps the policy in the React browser command layer. Core
fragment.delete does not need to guess whether an arbitrary expanded range
came from browser triple-click parity.
slate-react before Playwright rows that import package exports from
built dist.