TL;DR: Shift+Enter hard_break in list items causes content deletion on subsequent typing
I have a requirement where i am wrapping everything into a custom block which can have one or multiple nodes.
-
Custom schema with
customBlocknodes containingblock+content -
List items inside these blocks with schema:
list_item: { content: 'paragraph block*' } -
hard_breakdefined as:{ inline: true, group: 'inline', toDOM: () => ['br'], parseDOM: [{ tag: 'br' }] }
Desired behavior:
-
Enter in normal paragraph should create new
<custom-block><p></p></custom-block> -
Enter in list item → split list item (works fine using
splitListItem) -
Shift+Enter in list item → insert
hard_break(line break within same paragraph)
Implementation:
// Shift+Enter handler: Insert hard_break in tables/lists, new paragraph within custom block
// NOTE: hard_break in list items has known DOM observation issues in some browsers
// where typing after the break can cause content deletion. This is a ProseMirror limitation.
function handleShiftEnter(schema: Schema) {
return (state: EditorState, dispatch?: (tr: Transaction) => void) => {
const { $from, empty } = state.selection
if (!empty) return false
if (!dispatch) return true
// Tables/Lists → insert hard_break (line break within the same paragraph)
if (isInTable($from) || isInList($from)) {
const br = schema.nodes.hard_break.create()
const tr = state.tr.replaceSelectionWith(br).scrollIntoView()
dispatch(tr)
return true
}
// custom block/answer → new paragraph within SAME block
const customBlockDepth = findAncestorOfType($from, ['customBlock'])
if (blockDepth === -1) return false
const tr = state.tr
const depthToSplit = $from.depth - customBlockDepth
// Use tr.split with explicit attrs to prevent copying data-id from parent
if (depthToSplit > 0) {
tr.split($from.pos, depthToSplit, [
{ type: schema.nodes.paragraph, attrs: {} },
])
} else {
const newParagraph = schema.nodes.paragraph.create(editorOrigin)
tr.insert($from.pos, newParagraph)
}
dispatch(tr)
return true
}
}
Problem:
-
Shift+Enter inserts the
hard_breakcorrectly -
Typing any character immediately after causes content deletion
Demo:

