docs/solutions/logic-errors/2026-05-09-slate-v2-code-highlighting-tab-must-indent-selected-lines.md
The Slate v2 code-highlighting example handled Tab as plain text insertion. That was fine for a collapsed caret, but wrong for selected code lines.
Keep collapsed Tab simple, but route expanded selections inside one code block through line-start edits:
const handledCodeLines = updateSelectedCodeLines(
editor,
isShiftTab ? 'outdent' : 'indent'
)
if (!handledCodeLines && isTab) {
editor.update((tx) => {
tx.text.insert(CodeIndent)
})
}
updateSelectedCodeLines reads the current value and selection, finds selected
code-line children inside the same code-block, then inserts or removes the
indent string at each selected line's first text leaf.
The browser proof selects across two code lines, presses Tab, checks both lines are indented, selects again, presses Shift+Tab, and checks both lines return to their original text.
Collapsed code Tab is a caret text insertion. Expanded code Tab is structural line editing. Splitting those paths prevents the text insertion transform from deleting the selected code range.
The fix also keeps the behavior local to the example's accepted model: code
blocks are code-block elements containing code-line children. It does not
pretend to implement Lexical node keys, DOM export shape, language metadata,
highlighter transforms, line moving, or Home/End visual caret policy.