# Backspace and Enter (and Delete, I guess)

**URL:** <https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57>\
**Category:** Uncategorized\
**Created:** [November 3, 2015, 10:03am UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57 "2015-11-03T10:03:15Z")\
**Posts on this page:** 18\
**Page:** 1

<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:** [November 3, 2015, 10:03am UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/1 "2015-11-03T10:03:15Z")

</div>

So the initial ad-hoc behavior I programmed turned out to be [woefully inadequate](https://github.com/ProseMirror/prosemirror/issues/21) (to my defense, it wasn’t much worse than that in many widely used WYSIWYG tools). But I wanted to define these in a way that actually followed some principle more rigorous than ‘I guess this is sort of what other tools do’.

So I searched for literature on the subject. This was actually really hard to find—either I didn’t find the right jargon, or academics are so embarrassed by WYSIWYG-style editing interfaces that they refuse to touch them. But I did find a few useful papers, all of them by the Inria people (most norably Irène Vatton and Vincent Quint) working on a series of semantic editors: [Grif](http://www.unimelb.edu.au/sgml/unibook-user/3.html), [Thot](http://opera.inrialpes.fr/Thot/), and [Amaya](http://www.w3.org/Amaya/). Especially this [section of the Thot manual](http://opera.inrialpes.fr/Thot/Doc/Thotman-E4.html) and section 4.3 of this [paper on Amaya](https://hal.inria.fr/inria-00423365/document) were inspiring.

### Enter

Enter takes on various variations of the theme ‘_split_’. In the simple case of the cursor being in the middle of a textblock, it will split the textblock in two at the cursor position. If the cursor was at the end of the block, the newly split off block will be a regular paragraph, rather than inheriting the parent block’s type.

(Note that all these behaviors occur only as allowed by the schema – if the schema forbids the resulting document shape, the behavior will be suppressed and the next possible behavior will be tried.)

Enter at the start of a textblock does not split that block in two, but rather splits that block off from its enclosing block. If it has a sibling before it, the enclosing block is split above the cursor’s block. If not, the current block is lifted out of the enclosing block. If it has no enclosing block, I do currently fall back on the ‘split paragraph’ behavior (in this case, split off an empty paragraph). I’m still debating whether to do something else here. One option would be to do nothing, another would be to create that empty paragraph and immediately move the cursor into it.

So the typical illustration of this behavior is that you are in a list item (using a document schema that allows multiple blocks per list item), and you press enter. The first thing that happens is that you get a new paragraph inside of your current list item. (This is somewhat non-standard – most tools will immediately create a new list item. And many of them make it quite hard or even impossible to put multiple paragraphs inside of a single item.) To get a new list item, you have to press enter again, which will split the original list item above the new paragraph. Pressing enter again will lift your new paragraph out of the list. I think this is a rather nicely predictable (once you’ve seen it a few times), linear progression.

There’s a special case when the cursor is inside a block type that’s marked as containing code (such as code\_block). Since newlines in such blocks are meaningful, enter will insert a newline character. At the end of a code block, enter does move to the next paragraph (but you can use shift or ctrl-enter to insert a newline instead).

### Backspace

Backspace, then, is the ‘_join_’ operation, i.e. the inverse of Enter. Sometimes. At other times, such as when something is selected or the cursor is after text, it obviously deletes the selection or the character before the cursor.

But when pressed at the start of a textblock, it removes one ‘barrier’ between this textblock and the preceding node, where ‘_preceding node_’ is defined as either its preceding sibling, or if it’s a first child the sibling before its parent, or failing that the sibling before its grandparent, and so on.

If this preceding node is a leaf node, for example a horizontal rule, which can’t have child nodes, we can’t join with it, so we simply delete it. If there is no preceding node, we also can’t join, and we perform a ‘lift’ (moving out of a parent node) if possible.

If there is a non-leaf preceding node, we try to move the node with the cursor closer to it. If that node, or one of its ancestors, can be joined with the preceding node, we do that. Joining paragraphs together is a case of this, but it can also be used to join two adjacent lists or blockquotes together. Failing that, f the node with the cursor is directly after the preceding node (with no wrapping nodes around it), we try to move it into the preceding node. This allows you to backspace a paragraph after a list into that list (without immediately joining it with the last paragraph in the list).

Failing that, if the node with the cursor is wrapped relative to the preceding node, we again try to lift it up out of its wrappers. This means that if joining with or moving into a preceding node isn’t possible, backspace has the visually expected effect of rubbing out the nesting before the cursor.

The main departure relative to the convention used by most tools is that this approach to backspace will join at any block level, not only at the textblock level. I think there is value in having an intermediate step, which allows moving things into blocks without losing them as separate blocks. If you do want to join to the preceding textblock, pressing backspace again will do so.

### Delete

Delete acts like a sort of inversed backspace. It also deletes the selection, if any, or the character after the cursor. If those don’t apply, it looks for the block after the cursor, and again deletes that if it is a leaf block. If not, it applies the algorithm used by backspace to try and ‘pull’ the succeeding block closer to the cursor. This might pull a paragraph into a list, or might join a directly adjacent paragraph with the current textblock.

---

<div class="post-metadata">

**Author:** ![kiejo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kiejo/32/64_2.png) [@kiejo](https://discuss.prosemirror.net/u/kiejo)\
**Post date:** [November 5, 2015, 12:29pm UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/2 "2015-11-05T12:29:18Z")

</div>

Thanks for clearing this up. I think this is a good general solution to accommodate for different and flexible schema definitions that are not tied to any specific node types.

Unfortunately, the resulting default behavior in bullet lists is less than ideal for consumer facing products as most users expect the behavior of programs like Google Docs and Word, which is quite different. So my question is, what would be the best way to change the default behavior for bullet/ordered lists to behave more similarly to Google Docs. For example, I do not necessarily need to allow multiple paragraphs inside a list item and hitting enter should immediately create a new list item (instead of hitting enter twice).

It would be very helpful if you could provide some guidance on how to achieve this. One idea I have would involve creating a custom command, which first checks if the current selection is a list item, then performs the appropriate transformation and finally skips any other commands. Or is it maybe possible to define that kind of behavior inside a custom schema?

---

<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:** [November 5, 2015, 1:31pm UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/3 "2015-11-05T13:31:17Z")

</div>

> [@kiejo](#):
>
> Unfortunately, the resulting default behavior in bullet lists is less than ideal for consumer facing products as most users expect the behavior of programs like Google Docs and Word, which is quite different.

I strongly disagree. The behavior was designed to be close to other tools whenever it makes sense, and is intended as something that users can figure out easily. If it wasn’t, there would be no point to it.

You can define custom commands and bind keys to them, and you can change your schema to allow only inline content inside of list\_item nodes (in which case the existing commands will automatically do the thing you wanted). But what I’m working on here is fixing this type of interface. So ideally, unfixing it again shouldn’t be the first thing sites that integrate it do.

---

<div class="post-metadata">

**Author:** ![kiejo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kiejo/32/64_2.png) [@kiejo](https://discuss.prosemirror.net/u/kiejo)\
**Post date:** [November 5, 2015, 3:07pm UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/4 "2015-11-05T15:07:00Z")

</div>

> [@marijn](#):
>
> I strongly disagree. The behavior was designed to be close to other tools whenever it makes sense, and is intended as something that users can figure out easily. If it wasn’t, there would be no point to it.

Personally, I prefer the consistent and predictable interface you designed. The problem is that the majority of (non tech-affine) users are very resistant to changing their behavior or learning new tools, especially if they’ve been using other text editors in a different way their whole lives. In these cases, I’m convinced that sticking to conventions leads to a better overall user experience, even if these conventions might be inferior on a conceptual or rational level.

> [@marijn](#):
>
> you can change your schema to allow only inline content inside of list\_item nodes (in which case the existing commands will automatically do the thing you wanted)

This sounds like a good solution for what I’m trying to achieve. I will try that and see how it works.

> [@marijn](#):
>
> But what I’m working on here is fixing this type of interface. So ideally, unfixing it again shouldn’t be the first thing sites that integrate it do.

I see it the same way and am really resistant to changing the default behavior of ProseMirror, but our first usability tests showed us that the current handling of bullet lists is a major usability pain point in our internally used prototype.

---

<div class="post-metadata">

**Author:** ![yoshokatana](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/yoshokatana/32/72_2.png) [@yoshokatana](https://discuss.prosemirror.net/u/yoshokatana)\
**Post date:** [November 11, 2015, 2:49pm UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/5 "2015-11-11T14:49:58Z")

</div>

The redefinition of enter and backspace as _split_ and _join_ definitely matches the ideas I’ve been playing with, and I think it provides a lot of consistency among different document models.

One thing I really like (that I’ve struggled with) is the hierarchy of actions, especially around blockquotes and lists. In the project I’m currently working on, all of our wysiwyg areas are limited to inline elements (since they exist in block-level _components_ that technically live outside the confines of the wysiwyg interface). This was great for paragraphs, where we could use a [representational text model](https://github.com/nymag/text-model) to manage the splitting and joining of inline elements and the paragraphs themselves, but it breaks down the minute you go past that shallow structure.

I’ve hit a number of stumbling blocks now that I’m trying to tackle blockquotes (should they allow multiple paragraphs?), list items (same question), and dealing with things like multi-paragraph operations. The hierarchy of actions that you described seems like they’ll provide a consistent experience around those (and other complicated data structures).

---

<div class="post-metadata">

**Author:** ![kiejo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kiejo/32/64_2.png) [@kiejo](https://discuss.prosemirror.net/u/kiejo)\
**Post date:** [November 16, 2015, 8:30pm UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/6 "2015-11-16T20:30:58Z")

</div>

> [@yoshokatana](#):
>
> I’ve hit a number of stumbling blocks now that I’m trying to tackle blockquotes (should they allow multiple paragraphs?), list items (same question), and dealing with things like multi-paragraph operations.

I’m struggling with the same question as to whether to allow multiple paragraphs inside a list item by default or not. Currently, I tend towards choosing a default where only inline elements are allowed. A user would still be able to enforce multiple lines inside a list item by hitting Shift+Enter to create a break line. Are there any concrete practical benefits of allowing multiple paragraphs inside list items? Maybe there are some interesting use cases that I’m overseeing or that I simply haven’t thought of?

---

<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:** [November 16, 2015, 9:16pm UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/7 "2015-11-16T21:16:41Z")

</div>

> Are there any concrete practical benefits of allowing multiple paragraphs inside list items?

Nested lists are a pretty big one.

---

<div class="post-metadata">

**Author:** ![kiejo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kiejo/32/64_2.png) [@kiejo](https://discuss.prosemirror.net/u/kiejo)\
**Post date:** [November 17, 2015, 9:29am UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/8 "2015-11-17T09:29:40Z")

</div>

> [@marijn](#):
>
> Nested lists are a pretty big one.

You are right, nested lists are definitely very important. I guess that I didn’t think of them as “multiple paragraphs” from a user perspective. Only allowing inline elements in list items would prevent nested lists, as lists are represented as block elements, right? Disallowing nested lists would definitely be be too restrictive on the schema level. In that case I’m still not sure how I would disallow the possibility of creating multiple paragraphs inside a list item. Is it possible to specify multiple allowed child node types on the schema level? For example saying that a list item can only contain inline elements or lists. Is this something you have thought about? I saw that NodeTypes have a “kind” attribute, but I didn’t have the time to explore what they actually do yet.

---

<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:** [November 17, 2015, 12:01pm UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/9 "2015-11-17T12:01:10Z")

</div>

> [@kiejo](#):
>
> Is it possible to specify multiple allowed child node types on the schema level?

Yes, but it is not possible to mix inline and block content in a single node. You could allow only paragraphs and lists in list items if you wanted. You’d do so by labeling the paragraph and ordered/bullet lists with an extra kind (say `kind: "listable"`) and setting the content of list\_item to this kind (`contains: "listable"`).

---

<div class="post-metadata">

**Author:** ![funkyeah](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/f/f14d63/32.png) [@funkyeah](https://discuss.prosemirror.net/u/funkyeah)\
**Post date:** [November 19, 2015, 8:52am UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/10 "2015-11-19T08:52:22Z")

</div>

Weighing in on the _improved way_ vs. _standard way_ discussion.

> [@marijn](#):
>
> I strongly disagree. The behavior was designed to be close to other tools whenever it makes sense, and is intended as something that users can figure out easily. If it wasn’t, there would be no point to it. … But what I’m working on here is fixing this type of interface.

I think its good to carefully examine when something “makes sense” and what “fixing” means within the context above.

I certainly respect the goal of improving mechanics but WYSIWYM editors and the standard mechanics they ascribe to, are in lots of products users work in everyday. To the degree possible I’d prefer not to force my users to adopt any new mechanics only when using Prosemirror.

It doesn’t really matter if the end-user can figure out something easily, if it surprises them or is otherwise non-standard without providing obvious value to _them_ then it distracted them from what you as a developer want them focusing on and it could easily be taking away from their overall experience of the application Prosemirror is integrated into.

This is one area where I think a different default perspective is warranted from IDEs like CodeMirror. IDE using programmers are way more likely to value optimized mechanics and expect needing to learn them. WYSIWYM users are more likely to value following standard convention over improved mechanics.

So I truly believe that breaking with a standard convention should only “make sense” when absolutely unavoidable. If you have to break standard expectations to “fix” the interface and that learning process for the user takes non-zero time, then it will be _broken_ for each and every user before it is _fixed_ in their eyes. As it stands I do think a majority of integrators would opt to “unfix” anything that violates standard convention if given the choice.

---

<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:** [November 19, 2015, 12:20pm UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/11 "2015-11-19T12:20:37Z")

</div>

I’ve come to realize that having ‘auto splitting list items’ actually doesn’t interfere with the behavior I defined in any problematic way.

And I apologize about the angry tone I took in reply [#3](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/3). That was uncalled for and poorly thought through.

You can still, with a single backspace press, get back into your previous list item after pressing enter (when enter causes a list item split). The only tricky part is that it might not be entirely obvious anymore how to create a nested list. But if we take the approach proposed in [issue 70](https://github.com/ProseMirror/prosemirror/issues/70), and disallow creating a _directly_ nested list, and if that is tried in a list item that’s not the first item, to automatically join that item with the one above (creating the more typical structure of a list item with first a paragraph, and _then_ a nested list).

---

<div class="post-metadata">

**Author:** ![kiejo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kiejo/32/64_2.png) [@kiejo](https://discuss.prosemirror.net/u/kiejo)\
**Post date:** [November 19, 2015, 4:20pm UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/12 "2015-11-19T16:20:33Z")

</div>

> [@marijn](#):
>
> I’ve come to realize that having ‘auto splitting list items’ actually doesn’t interfere with the behavior I defined in any problematic way.

That’s great to hear!

> [@marijn](#):
>
> And I apologize about the angry tone I took in reply #3. That was uncalled for and poorly thought through.

No worries, I didn’t take it personally.

> [@marijn](#):
>
> You can still, with a single backspace press, get back into your previous list item after pressing enter (when enter causes a list item split). The only tricky part is that it might not be entirely obvious anymore how to create a nested list. But if we take the approach proposed in issue 70, and disallow creating a directly nested list, and if that is tried in a list item that’s not the first item, to automatically join that item with the one above (creating the more typical structure of a list item with first a paragraph, and then a nested list).

I really like this approach! It would make it much easier for new users to work with bullet lists while still adhering to the split/join principle you defined. So I guess this new behavior would be implemented on a command level and leave the current schema unchanged, right? Regarding nested lists, I would additionally suggest the introduction of hotkeys for indention/unindention like they were proposed in [issue 21](https://github.com/ProseMirror/prosemirror/issues/21#issuecomment-139857460). This should definitely help users create nested lists as these hotkeys are pretty common in other editors.

---

<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:** [November 24, 2015, 12:48pm UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/13 "2015-11-24T12:48:39Z")

</div>

The revised commands (both for list-wrapping and for list-item splitting) have been merged into master.

> [@kiejo](#):
>
> Regarding nested lists, I would additionally suggest the introduction of hotkeys for indention/unindention

I’m not doing indentation-vocabulary-based commands right now. Feel free to try to implement them yourself, but for now my intuition is that we can get by without them, and that having two different vocabularies for this kind of nesting manipulation built in is too much.

---

<div class="post-metadata">

**Author:** ![kiejo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kiejo/32/64_2.png) [@kiejo](https://discuss.prosemirror.net/u/kiejo)\
**Post date:** [November 26, 2015, 10:37am UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/14 "2015-11-26T10:37:29Z")

</div>

> [@marijn](#):
>
> The revised commands (both for list-wrapping and for list-item splitting) have been merged into master.

Awesome!! 😃One thing I noticed in the current master branch and the online demo is that it’s still possible to create a directly nested list item like described in [Issue 70](https://github.com/ProseMirror/prosemirror/issues/70).

> [@marijn](#):
>
> I’m not doing indentation-vocabulary-based commands right now. Feel free to try to implement them yourself, but for now my intuition is that we can get by without them, and that having two different vocabularies for this kind of nesting manipulation built in is too much.

Alright!

---

<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:** [November 26, 2015, 10:50am UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/15 "2015-11-26T10:50:53Z")

</div>

> [@kiejo](#):
>
> One thing I noticed in the current master branch and the online demo is that it’s still possible to create a directly nested list item

How? (As in, what actions are you taking.)

---

<div class="post-metadata">

**Author:** ![kiejo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kiejo/32/64_2.png) [@kiejo](https://discuss.prosemirror.net/u/kiejo)\
**Post date:** [November 26, 2015, 10:55am UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/16 "2015-11-26T10:55:46Z")

</div>

> [@marijn](#):
>
> How? (As in, what actions are you taking.)

For example: Hit "\* " and then "\* " again.

---

<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:** [November 26, 2015, 11:15am UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/17 "2015-11-26T11:15:55Z")

</div>

Yes, I was talking about the ‘wrap in list’ menu buttons. If you type '\* ’ at the top of a list item, you are suggesting really strongly that you want to create a sublist there (visually, you created two bullets next to each other), so I don’t think having that actually create a sublist is a problem.

---

<div class="post-metadata">

**Author:** ![kiejo](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/kiejo/32/64_2.png) [@kiejo](https://discuss.prosemirror.net/u/kiejo)\
**Post date:** [November 26, 2015, 11:43am UTC](https://discuss.prosemirror.net/t/backspace-and-enter-and-delete-i-guess/57/18 "2015-11-26T11:43:30Z")

</div>

> [@marijn](#):
>
> Yes, I was talking about the ‘wrap in list’ menu buttons. If you type '\* ’ at the top of a list item, you are suggesting really strongly that you want to create a sublist there (visually, you created two bullets next to each other), so I don’t think having that actually create a sublist is a problem.

Ah ok, makes sense!
