# Add better undo support when inserting formatted text

**URL:** https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821
**Category:** Feature
**Created:** [January 14, 2022, 4:16am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821 "2022-01-14T04:16:44Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![seanblue](https://avatars.discourse-cdn.com/v4/letter/s/dc4da7/32.png) [@seanblue](https://meta.discourse.org/u/seanblue)
#### Post date: [January 14, 2022, 4:16am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/1 "2022-01-14T04:16:44Z")

</div>

Right now in Discourse, if you paste plain text into the composer, typical browser behavior via Ctrl+Z will undo that paste and remove the pasted text. However, if you paste formatted text **such as this bold text** , undo doesn’t work. Similarly, pasting links on top of text to linkify them cannot be undone, nor can the markdown inserted via shortcuts like Ctrl+B or when adding formatting from the composer toolbar options. Ideally, as much of this as possible would be added to the undo stack so Ctrl+Z works.

Let me give a description of what happens to me fairly often.

1. I copy some text from another website which happens to be a link, bold, a header, etc. (Sometimes this fact registers and sometimes it does not.)
2. I go to Discourse to paste this text into my already partially written post.
3. I hit Ctrl+V which inserts the formatted text.
4. I realize my mistake and hit Ctrl+Z, which does nothing.
5. I manually remove the formatted text that I inserted by mistake. (Most often it’s the linked version that I pasted by mistake, so not like I just have to remove a `#` or something like that.)
6. I hit Ctrl+Shift+V which I should have done the first time to paste the unformatted text.

Obviously this is in part user error, and when I don’t mess up it’s only two steps (copy from other website, paste as plain text in Discourse). But when I do mess up (which is often since I’m used to just hitting Ctrl+V given that most websites don’t do formatted pasting) it would be nice if I could save some time by Ctrl+Z working like normal.

---

<div class="post-metadata">

### Author: ![codinghorror](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/codinghorror/32/110067_2.png) [@codinghorror](https://meta.discourse.org/u/codinghorror)
#### Post date: [January 14, 2022, 6:46pm UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/2 "2022-01-14T18:46:18Z")

</div>

This is generally a native browser behavior, and isn’t something Discourse is doing. Try testing against a plain text box in HTML.

---

<div class="post-metadata">

### Author: ![seanblue](https://avatars.discourse-cdn.com/v4/letter/s/dc4da7/32.png) [@seanblue](https://meta.discourse.org/u/seanblue)
#### Post date: [January 14, 2022, 7:02pm UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/3 "2022-01-14T19:02:46Z")

</div>

Right, undo doesn’t work by default whenever you use JavaScript to modify an input. But I googled around and found that [`document.execCommand`](https://stackoverflow.com/questions/27027833/is-it-possible-to-edit-a-text-input-with-javascript-and-add-to-the-undo-stack) can insert text while appending to the undo stack.

For example, if you do `document.getElementById('myInput').value = 'asd'` and then Ctrl+Z, it won’t undo.

But if you do `document.execCommand('insertText', false, 'asd')` while the cursor is where you want it (which it should be based on the current Discourse workflow), the text is properly inserted and Ctrl+Z will remove the added text as expected.

Basically, I’m wondering if `document.execCommand` (or some other process if another approach is considered better) can be used to append to the undo stack so Ctrl+Z works in these cases.

---

<div class="post-metadata">

### Author: ![codinghorror](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/codinghorror/32/110067_2.png) [@codinghorror](https://meta.discourse.org/u/codinghorror)
#### Post date: [January 14, 2022, 8:03pm UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/4 "2022-01-14T20:03:18Z")

</div>

No — we intentionally pulled that support from Discourse years ago in favor of letting the browser native text box undo handling work as it should across all standard websites.

---

<div class="post-metadata">

### Author: ![seanblue](https://avatars.discourse-cdn.com/v4/letter/s/dc4da7/32.png) [@seanblue](https://meta.discourse.org/u/seanblue)
#### Post date: [January 14, 2022, 9:07pm UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/5 "2022-01-14T21:07:40Z")

</div>

> [@codinghorror](#):
>
> we intentionally pulled that support from Discourse years ago in favor of letting the browser native text box undo handling work as it should across all standard websites.

I think I must be missing something. What does “letting the browser native text box undo handling work” mean exactly? As far as I can tell, undo for formatted text doesn’t work _at all_ in Discourse, so are you saying that undo not working _is_ standard website behavior?

The reason I’m confused is because I can’t think of a single website (other than things like Microsoft Word where undo works) that supports formatted paste besides Discourse. So I have nothing to compare Discourse to in order to see what is “standard”. If you could point me towards a few websites for comparison that would be really helpful.

---

<div class="post-metadata">

### Author: ![codinghorror](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/codinghorror/32/110067_2.png) [@codinghorror](https://meta.discourse.org/u/codinghorror)
#### Post date: [January 14, 2022, 11:42pm UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/6 "2022-01-14T23:42:48Z")

</div>

See

> **[W3Schools.com](https://www.w3schools.com/tags/tag_textarea.asp)**
>
> W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

Press **Try it yourself** , then enter text in the textbox, pause, then press ctrl+z to undo your actions. Here’s a demo. First we press the **Try it yourself** button, which results in a HTML `<textarea>` being displayed in the browser.

 ![image](https://global.discourse-cdn.com/meta/original/3X/7/2/7212c498b821e3663990d99a4e1371c6223ea92d.png)

I enter some text into the textbox. As you can see in the screenshot, I typed

> I JUST TYPED THIS TEXT YAYYYY!

 ![image](https://global.discourse-cdn.com/meta/original/3X/1/2/12214706ccb632fbfa59d2119c38e703b7543229.png)

Now, after typing, I press ctrl+z to undo my typing, and I see this:

 ![image](https://global.discourse-cdn.com/meta/original/3X/b/d/bd5f5564e96b6a5a255bc6970edddef13180089f.png)

Note that the text has returned to its previous state, and this was 100% handled by the browser itself, zero JavaScript code is involved.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [January 15, 2022, 12:09am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/7 "2022-01-15T00:09:11Z")

</div>

My understanding is that @seanblue is asking if we can amend the browser APIs we use when we manipulate the textarea to better hint the browser so it can handle undo a bit better. So this would only apply to keyboard shortcuts, and toolbar, upload and stuff like that

I am not against tuning stuff here, but I worry that some off these APIs will require lots of care, there is certainly risk of regressions

Not against experiments here, maybe if the community wish to send through some PRs to show us how it is done

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [January 15, 2022, 12:27am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/8 "2022-01-15T00:27:55Z")

</div>

We could definitely do better here. A lot of our toolbar buttons and fancy-paste behaviour directly set the value of the textarea in JavaScript. This totally breaks the native browser undo/redo history.

Instead, whenever we make programmatic modifications to the textarea, we should be using `document.execCommand` (as @seanblue mentioned). That way, the browser interprets it the same as a user action, and inserts it cleanly into the undo/redo history.

> **[Document: execCommand() method - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand)**
>
> The execCommand method implements multiple different commands. Some of them provide access to the clipboard, while others are for editing form inputs, contenteditable elements or entire documents (when switched to design mode).

> the `insertText` command, which you can use to programmatically replace text at the cursor while preserving the undo buffer (edit history) in plain `textarea` and `input` elements.

---

<div class="post-metadata">

### Author: ![seanblue](https://avatars.discourse-cdn.com/v4/letter/s/dc4da7/32.png) [@seanblue](https://meta.discourse.org/u/seanblue)
#### Post date: [January 15, 2022, 12:28am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/9 "2022-01-15T00:28:05Z")

</div>

But that textbox doesn’t handle formatted text, which isn’t what I’m talking about. I know that browsers handle undoing normally typed and pasted text. My point is that Discourse doesn’t handle undoing pasted formatted text. Follow these steps to see what I’m talking about.

First, open the Discourse composer:

 ![image](https://global.discourse-cdn.com/meta/original/3X/d/2/d248000b4957d2cfe2d2dcc1df61cc87dd0b9edd.png)

Now copy the following text and paste it into the composer: this is a test

 ![image](https://global.discourse-cdn.com/meta/original/3X/7/1/7176a039c256c3c6d7de6432e5e0c1512b69eac2.png)

Now hit ctrl+z, and the pasted text is removed. This is identical to the behavior you demonstrated in your post.

 ![image](https://global.discourse-cdn.com/meta/original/3X/a/6/a6d41ed9abcd011ba9bb1e9709bc4c92d1c25edb.png)

Now copy the following text instead and paste it into the composer: this is a _great_ test  
Notice that it pastes it with the markdown to italicize “great”.

 ![image](https://global.discourse-cdn.com/meta/original/3X/7/7/7732db1ec9417336b638b3f25db32cb7d27d5ef9.png)

Now hit ctrl+z and notice that the pasted text is still there. This is what I’ve been talking about.

 ![image](https://global.discourse-cdn.com/meta/original/3X/7/7/77b0f4f76df2e343c29299a72bb28b2cbe5e76dc.png)

* * *

> [@sam](#):
>
> My understanding is that @seanblue is asking if we can amend the browser APIs we use when we manipulate the textarea to better hint the browser so it can handle undo a bit better. So this would only apply to keyboard shortcuts, and toolbar, upload and stuff like that

That’s right. I’m not suggesting handling the undo yourself in JavaScript. I’m suggesting that when you manipulate the textarea, let the browser know so it can undo the change itself when the user hits ctrl+z.

> [@sam](#):
>
> I am not against tuning stuff here, but I worry that some off these APIs will require lots of care, there is certainly risk of regressions

For what it’s worth, 99% of my frustration would be resolved if ctrl+z worked after pasting formatted text. Would it be ideal if every single operation could be undone with ctrl+z? Sure. But most other operations can be undone by repeating the original operation (e.g. doing ctrl+b can both add and remove bold markdown). But with paste, it has the potential to include a significant amount of unexpected markdown, including headers, links, and even tables, which is why it’s so important that undo works in that case.

If we narrowed the scope to just handling undo in the formatted paste case and ignored other shortcuts, toolbar buttons, etc., would that reduce the risk enough to give it a shot?

---

<div class="post-metadata">

### Author: ![codinghorror](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/codinghorror/32/110067_2.png) [@codinghorror](https://meta.discourse.org/u/codinghorror)
#### Post date: [January 15, 2022, 3:11am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/10 "2022-01-15T03:11:08Z")

</div>

I see; between your and @david’s explanation, I understand the distinction. I just never really use those buttons in the editor for the most part. I type things in the textbox using my computer’s keyboard (either physical or on-screen), and this is handled seamlessly by the browser.

---

<div class="post-metadata">

### Author: ![seanblue](https://avatars.discourse-cdn.com/v4/letter/s/dc4da7/32.png) [@seanblue](https://meta.discourse.org/u/seanblue)
#### Post date: [January 15, 2022, 3:41am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/11 "2022-01-15T03:41:56Z")

</div>

That’s understandable. I also tend to type the markdown instead of using the toolbar buttons for that, so that aspect isn’t really an issue for me. I only mentioned the toolbar stuff in the OP to point out that it doesn’t _just_ happen when pasting formatted text. Being able to undo the toolbar actions isn’t super important because the user is doing those actions intentionally. But when pasting, the formatting is often incidental and unexpected, so being able to undo that would be very convenient.

---

<div class="post-metadata">

### Author: ![seanblue](https://avatars.discourse-cdn.com/v4/letter/s/dc4da7/32.png) [@seanblue](https://meta.discourse.org/u/seanblue)
#### Post date: [February 2, 2022, 2:52am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/12 "2022-02-02T02:52:57Z")

</div>

Just wanted to follow up on this one and see the likelihood of this being worked on any time in the foreseeable future.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [February 2, 2022, 5:56am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/13 "2022-02-02T05:56:46Z")

</div>

Not scheduled yet, but yes, it appears to do the trick. I think we should change our implementation for both toolbar and stuff like CTRL-B shortcuts and mentions.

It is a pretty involved change though, I would say it would take about 1-3 weeks of work to get this all wired in. There is a lot of surface area:

- Cut-and-paste images
- Uploads
- Bold / Italic
- Links
- @mentions
- #autocomplete

https://codepen.io/SamSaffron/embed/preview/QWONrzy?default-tabs=js%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=QWONrzy

I support this change but am just not sure when we can schedule it… I guess I am ok to slot it for our next release, any objections @codinghorror ?

I do like that you will be able to CTRL-Z all the way back to an empty box instead of just be blocked on your first mention, link, etc…

---

<div class="post-metadata">

### Author: ![seanblue](https://avatars.discourse-cdn.com/v4/letter/s/dc4da7/32.png) [@seanblue](https://meta.discourse.org/u/seanblue)
#### Post date: [February 2, 2022, 12:26pm UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/14 "2022-02-02T12:26:05Z")

</div>

> [@sam](#):
>
> It is a pretty involved change though, I would say it would take about 1-3 weeks of work to get this all wired in. There is a lot of surface area

One nice thing is that (in my opinion) it can reasonably be done incrementally rather than having to release it all at once. Obviously I don’t know if that’ll be the case from a technical perspective, but from a user perspective I think it would be fine. Some logical separations might be:

- Pasting text that becomes formatted, including things like bold, images, and links
- Autocompleting mentions, categories/tags, emoji
- Keyboard shortcuts like Ctrl+B for bold
- Toolbar actions, like bold, hide details, blur spoilers, etc.

I feel like each of those groups could be done individually without confusing users, and personally that’s the order I’d implement it in.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [February 7, 2022, 2:15am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/15 "2022-02-07T02:15:37Z")

</div>

I am slotting this work for our next release, it means we will get this cleaned up over the next 6 months or so, will not happen overnight, but we will make progress here.

---

<div class="post-metadata">

### Author: ![seanblue](https://avatars.discourse-cdn.com/v4/letter/s/dc4da7/32.png) [@seanblue](https://meta.discourse.org/u/seanblue)
#### Post date: [June 5, 2022, 2:06am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/16 "2022-06-05T02:06:21Z")

</div>

Since it’s been four months I wanted to check in and see how this was coming along. 🙂

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [June 6, 2022, 4:16am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/17 "2022-06-06T04:16:09Z")

</div>

Yes I completely hear you, but this is going to take a while longer.

It has kind of snowballed into a complete refactor needed on the composer. Our long term plan is to support a different abstraction layer for the composer which is now glued SUPER hard into it always being a TEXTAREA element.

The first unblocking move is supporting a contenteditable composer that looks and acts like our current text area.

I do not see us starting on this project for 3 more months, cause we have 3 other very large projects in front of it, but I do certainly see us getting a start on this project this year.

---

<div class="post-metadata">

### Author: ![seanblue](https://avatars.discourse-cdn.com/v4/letter/s/dc4da7/32.png) [@seanblue](https://meta.discourse.org/u/seanblue)
#### Post date: [June 7, 2022, 12:42am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/18 "2022-06-07T00:42:00Z")

</div>

> [@sam](#):
>
> Yes I completely hear you, but this is going to take a while longer.

No worries, was just looking for an update.

> [@sam](#):
>
> The first unblocking move is supporting a contenteditable composer that looks and acts like our current text area.

Whoa, I had never even heard of `contenteditable` until now. Do you mind sharing a brief technical explanation of why this change is needed/desirable? If not that’s fine, I’m just curious.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [June 7, 2022, 5:36am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/19 "2022-06-07T05:36:19Z")

</div>

> [@seanblue](#):
>
> Do you mind sharing a brief technical explanation of why this change is needed/desirable?

It is somewhat complicated, but we do want to enter the world of experimenting with rich editors. This would unlock that.

The reason this work is on the critical path is that our entire internals are heavily coupled to a specific implementation (TEXTAREA). We don’t have a single function to interface with the composer, it is more like cut-and-paste 20 different implementations.

What we would like to do is have a little “skeleton” component that says

- This is how you select text
- This is how you insert text

And so on… then we can re-implement the skeleton as a contenteditable or an undo friendly implementation of TEXTAREA.

A lot of code though needs to move to allow for this.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [June 10, 2022, 11:14am UTC](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821/22 "2022-06-10T11:14:40Z")

</div>

I was able to make a little progress here:

[https://github.com/discourse/discourse/commit/75d9c16156f79f5a9f30a04433c3cb0ae82d914c](https://github.com/discourse/discourse/commit/75d9c16156f79f5a9f30a04433c3cb0ae82d914c)

This is nowhere near as comprehensive as the long-term work @sam described. But I think it should help in the short-term. This should preserve undo history when pasting rich text, quoting, and when using (most) composer buttons/keyboard-shortcuts.

It’s live on Meta now - shout if you notice any issues.

[Next page](https://meta.discourse.org/t/add-better-undo-support-when-inserting-formatted-text/214821.md?page=2)
