# (help needed) \`Shift+Enter\` for hard\_break is creating invalidated transactions

**URL:** <https://discuss.prosemirror.net/t/help-needed-shift-enter-for-hard-break-is-creating-invalidated-transactions/8920>\
**Category:** Uncategorized\
**Created:** [January 6, 2026, 2:56pm UTC](https://discuss.prosemirror.net/t/help-needed-shift-enter-for-hard-break-is-creating-invalidated-transactions/8920 "2026-01-06T14:56:01Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![rohitt-gupta](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/rohitt-gupta/32/4614_2.png) [@rohitt-gupta](https://discuss.prosemirror.net/u/rohitt-gupta)\
**Post date:** [January 6, 2026, 2:56pm UTC](https://discuss.prosemirror.net/t/help-needed-shift-enter-for-hard-break-is-creating-invalidated-transactions/8920/1 "2026-01-06T14:56:01Z")

</div>

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 `customBlock` nodes containing `block+` content

- List items inside these blocks with schema: `list_item: { content: 'paragraph block*' }`

- `hard_break` defined 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:**

```typescript
// 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:**

1. Shift+Enter inserts the `hard_break` correctly

2. Typing any character immediately after causes content deletion

**Demo:**

![CleanShot 2026-01-06 at 20.25.01](https://discuss.prosemirror.net/uploads/secondsite/original/2X/0/0dc8747a9d0a80e810df3c7e6ddf7e23735dfa92.gif)

---

<div class="post-metadata">

**Author:** ![rohitt-gupta](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/rohitt-gupta/32/4614_2.png) [@rohitt-gupta](https://discuss.prosemirror.net/u/rohitt-gupta)\
**Post date:** [January 6, 2026, 3:26pm UTC](https://discuss.prosemirror.net/t/help-needed-shift-enter-for-hard-break-is-creating-invalidated-transactions/8920/2 "2026-01-06T15:26:39Z")

</div>

I have tried to use a simpler version of `shift + enter`

```typescript
function handleShiftEnter(schema: Schema) {
  const br = schema.nodes.hard_break
  return chainCommands(
    exitCode,
    (state: EditorState, dispatch?: (tr: Transaction) => void) => {
      if (dispatch)
        dispatch(state.tr.replaceSelectionWith(br.create()).scrollIntoView())
      return true
    }
  )
}

```

I still face the same issue.

![CleanShot 2026-01-06 at 20.55.41](https://discuss.prosemirror.net/uploads/secondsite/original/2X/b/b175d1023f497d9e21c7e7e3a0e5708c131c8d61.gif)

---

<div class="post-metadata">

**Author:** ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)\
**Post date:** [January 6, 2026, 3:42pm UTC](https://discuss.prosemirror.net/t/help-needed-shift-enter-for-hard-break-is-creating-invalidated-transactions/8920/3 "2026-01-06T15:42:38Z")

</div>

If you mean by ‘invalid transaction’ that applying the step crashes, `replaceSelectionWith` should not be capable of that. If you are seeing that, could you create a minimal schema and script that reproduces it?
