# Setting selection to a part of a large insert in a transaction

**URL:** <https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287>\
**Category:** Uncategorized\
**Created:** [March 26, 2025, 12:35am UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287 "2025-03-26T00:35:44Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![hypermoose](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/hypermoose/32/4510_2.png) [@hypermoose](https://discuss.prosemirror.net/u/hypermoose)\
**Post date:** [March 26, 2025, 12:35am UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/1 "2025-03-26T00:35:44Z")

</div>

I think I have a misunderstanding of how transactions and selection work.

I have a transaction where I insert a large amount of content at the end of a document and I want to have the selection move into that new content at a given offset. I can’t make it work in a single transaction without getting RangeErrors on the tr.setSelection call. The only way I can get it to work is in a setTimeout call after dispatching the insert transaction. What am I missing this can’t be normal.

---

<div class="post-metadata">

**Author:** ![prosed](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/p/aeb1de/32.png) [@prosed](https://discuss.prosemirror.net/u/prosed)\
**Post date:** [March 26, 2025, 1:33am UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/2 "2025-03-26T01:33:10Z")

</div>

What if you dispatch the transaction and then make a new one to set the selection?

---

<div class="post-metadata">

**Author:** ![hypermoose](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/hypermoose/32/4510_2.png) [@hypermoose](https://discuss.prosemirror.net/u/hypermoose)\
**Post date:** [March 26, 2025, 1:43am UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/3 "2025-03-26T01:43:52Z")

</div>

> [@prosed](#):
>
> e transaction and then make a new one to set the selection?

Back to back transactions with separate dispatches fail as well.

---

<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:** [March 26, 2025, 6:15am UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/4 "2025-03-26T06:15:45Z")

</div>

You should definitely be able to set a new selection in the same transaction that inserts content. Dispatching multiple transactions for that isn’t necessary (and is generally a bad idea). Can you show the code that creates this transaction?

---

<div class="post-metadata">

**Author:** ![hypermoose](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/hypermoose/32/4510_2.png) [@hypermoose](https://discuss.prosemirror.net/u/hypermoose)\
**Post date:** [March 26, 2025, 8:03pm UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/5 "2025-03-26T20:03:02Z")

</div>

Here is a block of code that demonstrates what I am trying to do and does not work. I added a comment to explain the range error as that part was my misunderstanding

```auto
       import { DOMParser as ProseMirrorDOMParser } from "prosemirror-model";
...
        let sequence = "<p>Test line just for content to test with</p>"
        let html = sequence.repeat(200)

        const domParser = new DOMParser();
        const parsedHTML = domParser.parseFromString(html, "text/html").body;

        // Convert DOM to ProseMirror-compatible document fragment
        const docNode = ProseMirrorDOMParser.fromSchema(editor.schema).parse(parsedHTML);

        // Put the cursor at the end of first Child or 2 if for some reason this fails
        const pos = docNode.firstChild?.nodeSize ?? 2

        tr = tr.insert(0, docNode)

        // This version never does anything
        //tr = tr.setSelection(TextSelection.create(tr.doc, 0, pos - 1 ))

        // Nor does this but its essentially the same
        const resolvedPos = tr.doc.resolve(pos - 1);
        tr = tr.setSelection(TextSelection.create(tr.doc, 0, resolvedPos.pos))

        // This one throws the Range Error which I understand is correct because I misunderstood that pos has to be 
        // a position before the insert
        //const mappedPos = tr.mapping.map(pos);
        //tr = tr.setSelection(TextSelection.create(tr.doc, 0, mappedPos))

        dispatch(tr);

```

---

<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:** [March 27, 2025, 5:54am UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/6 "2025-03-27T05:54:53Z")

</div>

There’s no guarantee that the content in `docNode` can be inserted in the document as-is. (In fact, it’s unlikely that your document node type allows itself as a child, so it’ll definitely get mangled by the replace logic, in the process of being inserted.) As such, blindly using the side of its first (?) child as a document position isn’t safe. You could try `tr.mapping.map(0, 1)` to find the position after the insertion.

And you’ll want to use [`TextSelection.between`](https://prosemirror.net/docs/ref/#state.TextSelection%5Ebetween) with the resolved position, not `create`, when you aren’t certain that the position is a valid inline position.

---

<div class="post-metadata">

**Author:** ![hypermoose](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/hypermoose/32/4510_2.png) [@hypermoose](https://discuss.prosemirror.net/u/hypermoose)\
**Post date:** [March 29, 2025, 4:52pm UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/7 "2025-03-29T16:52:50Z")

</div>

> [@hypermoose](#):
>
> ```auto
> let sequence = "<p>Test line just for content to test with</p>"
> let html = sequence.repeat(200)
> 
> const domParser = new DOMParser();
> const parsedHTML = domParser.parseFromString(html, "text/html").body;
> 
> // Convert DOM to ProseMirror-compatible document fragment
> const docNode = ProseMirrorDOMParser.fromSchema(editor.schema).parse(parsedHTML);
> 
> // Put the cursor at the end of first Child or 2 if for some reason this fails
> const pos = docNode.firstChild?.nodeSize ?? 2
> 
> tr = tr.insert(0, docNode)
> 
> // This version never does anything
> //tr = tr.setSelection(TextSelection.create(tr.doc, 0, pos - 1 ))
> 
> // Nor does this but its essentially the same
> const resolvedPos = tr.doc.resolve(pos - 1);
> tr = tr.setSelection(TextSelection.create(tr.doc, 0, resolvedPos.pos))
> 
> // This one throws the Range Error which I understand is correct because I misunderstood that pos has to be 
> // a position before the insert
> //const mappedPos = tr.mapping.map(pos);
> //tr = tr.setSelection(TextSelection.create(tr.doc, 0, mappedPos))
> 
> dispatch(tr);
> 
> ```

Changing to this does not work either. No logged error and resolved positions are 0 and 40 so something should have been selected within that region as the content in the transaction does appear in the doc

```auto
        const startPos = tr.doc.resolve(0);
        const resolvedPos = tr.doc.resolve(pos - 1);
        tr = tr.setSelection(TextSelection.between(startPos, resolvedPos))

```

---

<div class="post-metadata">

**Author:** ![hypermoose](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/hypermoose/32/4510_2.png) [@hypermoose](https://discuss.prosemirror.net/u/hypermoose)\
**Post date:** [April 11, 2025, 9:08pm UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/8 "2025-04-11T21:08:35Z")

</div>

Sorry to be a pest but any insight to what I might be doing wrong with my latest updated? @marijn

---

<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:** [April 12, 2025, 10:50am UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/9 "2025-04-12T10:50:12Z")

</div>

Look, `new DOMParser()`, without arguments, isn’t a thing in ProseMirror’s interface, and neither does `DOMParser` have a `parseFromString` method, so I wasn’t able to do anything with that code.

---

<div class="post-metadata">

**Author:** ![hypermoose](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/hypermoose/32/4510_2.png) [@hypermoose](https://discuss.prosemirror.net/u/hypermoose)\
**Post date:** [April 12, 2025, 4:32pm UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/10 "2025-04-12T16:32:02Z")

</div>

Oh sorry, DOMParser is a built in wrapper from typescript

---

<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:** [April 12, 2025, 7:16pm UTC](https://discuss.prosemirror.net/t/setting-selection-to-a-part-of-a-large-insert-in-a-transaction/8287/11 "2025-04-12T19:16:55Z")

</div>

I see. Including the `import` statements would have helped there. I don’t really understand what you’re trying to do, but `setSelection` with the result of `TextSelection.between` seems to work fine for me.
