docs/solutions/logic-errors/2026-04-17-custom-block-start-list-rules-must-delete-matched-marker-text.md
Modern list markdown rules promoted the paragraph into a list item, but they left the shorthand marker text behind in the live editor.
The most obvious repro was /blocks/list-demo: typing - produced a list
paragraph whose text was still -.
createRuleFactory(... type: 'blockStart' ...) only performs built-in matched
text deletion when the rule uses the default block-start apply path.
Modern list rules supplied custom apply functions:
That meant the shorthand marker range was never deleted unless the rule did it manually.
list-classic already handled this correctly by deleting match.range inside
its custom apply path. Modern list rules did not.
Make modern list rules mirror list-classic:
match.range inside custom applytoggleList(...)resolveMatch: ({ range }) => ({ range }),
apply: ({ editor }, match) => {
editor.tf.delete({ at: match.range });
toggleList(editor, { listStyleType: KEYS.ul });
return true;
}
For ordered lists, keep the parsed start number and the range together:
resolveMatch: ({ match, range }) => ({
range,
start: Number((match as RegExpMatchArray)[1]),
})
The list transform itself was fine. The broken part was the missing cleanup step before the transform.
Once the marker range is deleted first, the promoted list paragraph starts
empty and selection lands at [0, 0] offset 0, which is what the live
editor should have done all along.
blockStart apply handlers inherit matched-text cleanup.apply, add one regression for:
list-classic and modern list disagree, inspect the cleanup path
before touching normalization or rendering.bun test packages/list/src/lib/inputRules.spec.tsx
bun test ./apps/www/src/__tests__/package-integration/list/current-kit.slow.tsx
bun test ./apps/www/src/__tests__/package-integration/playground/playground-rules.slow.tsx
pnpm turbo build --filter=./packages/list --filter=./packages/link --filter=./apps/www
pnpm turbo typecheck --filter=./packages/list --filter=./packages/link --filter=./apps/www
pnpm lint:fix
Browser proof:
browser-use load of http://localhost:3001/blocks/list-demo- [0, 0], offset 0