When you backspace all the way to the beginning of a <li>
tag within a content editable <ul>
tag, all of the remaining <li>
tags are deleted.
<ul contenteditable="true">
<li>Hello</li>
<li>World</li>
</ul>
jsfiddle: /
Put your cursor after the 'd' in world and backspace all the way to the beginning of the line. When you hit backspace again, it will also delete the 'Hello' list item. How can you prevent this behavior?
UPDATE: It looks like this behavior only exists in Chrome
When you backspace all the way to the beginning of a <li>
tag within a content editable <ul>
tag, all of the remaining <li>
tags are deleted.
<ul contenteditable="true">
<li>Hello</li>
<li>World</li>
</ul>
jsfiddle: http://jsfiddle/8Q53V/
Put your cursor after the 'd' in world and backspace all the way to the beginning of the line. When you hit backspace again, it will also delete the 'Hello' list item. How can you prevent this behavior?
UPDATE: It looks like this behavior only exists in Chrome
Share Improve this question edited Jun 13, 2014 at 20:48 tilleryj asked Jun 12, 2014 at 15:43 tilleryjtilleryj 14.4k3 gold badges25 silver badges22 bronze badges 2- Nope, it happens for me in firefox too. – Costa Michailidis Commented Jul 21, 2014 at 21:27
- 1 PS: None of the solutions below for for me (Summer 2014). – Costa Michailidis Commented Jul 21, 2014 at 21:30
3 Answers
Reset to default 8This is what I have found:
The erronous behavior of contenteditable lists in Opera and Chrome only occurs if the parent
ul
element is not followed by any other element with a minimum rendering space of 1px x 1px. Thedisplay
value of the element doesn't matter, as long as it is non-empty or has a set height dimension with CSS.
So adding a simple <div style="height: 1px;">
will answer your most direct question.
However, You can't reliably use contenteditable
lists in HTML at the time of asking.
This question intrigued me and I tested it on Moz FF 29-30, Opera 21, Google Chrome 35 & IE 11, on Win 8.1 . I tested simple keys like Enter, Backspace and Delete.
TL;DR: IE 11 pletely messes up, Opera & Chrome do pretty good if the
ul
is followed by an element with a rendered size, and Moz FF inserts a weird<br type="_moz"></br>
tag. You would neede.preventDefault()
,e.keyCode/charCode
and theSelection
&Range
JS API to create a custom contenteditable list that works consistently across all browsers. However, these prerequisites already don't work consistently on all browsers. Best solution: use existing editors or some invisible text input for input.
These are the detailed gotcha's:
Hitting Enter to add a new li
will add the following markup:
- Opera and Google Chrome:
<li><br><li>
- Moz FF:
<li><br type="_moz"></br>
- IE 11: if the active
li
is non-empty:<li><br></li>
, if it is empty, IE pletely messes up & inserts ap
, then duplicates an empty<ul contenteditable="">
after it, with only a<br>
tag inside. This emptyul
will be added after the element following the original element, if any.
Hitting Backspace to remove a li:not(:first-child)
will do the following:
- Opera and Google Chrome: if the
ul
is not followed by an element with a rendered size, allli
's will be deleted. If it is, the expected behavior occurs. (oneli
is removed). - Moz FF: The expected behavior occurs (one
li
is removed). However, Moz FF moves the cursor out of the contenteditable area after removing ali
. - IE 11: Same behavior as when hitting Enter.
Hitting Backspace to remove the first li
should be prevented at all costs.
For every browser tested, this breaks the list lay-out. All new Enter hits will generate div
's as direct children of the list.
Hitting Delete to remove a subsequent li
works consistently across all tested browsers. The subsequent li
will be removed, and any content inside it will be transferred to the current li
Typing the first letter in an empty li
will do the following:
- Opera, IE11 and Google Chrome: The letter is printed. The automatically inserted
<br>
tag is removed. - Moz FF: The letter is printed. The custom
<br type="_moz">
tag is not removed.
Removing the only letter in an empty li
will do the following:
- Opera, IE11 and Google Chrome: Another
<br>
tag is automatically inserted. - Moz FF: Nothing. The custom
<br type="_moz">
is still present.
Fiddle: http://jsfiddle/8Q53V/8/ (first ul is with custom coded behavior, not perfect, second ul is standard)
You need to use contenteditable
on each of the li
tag
Demo
If you don't want to assign the attribute by yourself, you can use Javascript setAttribute()
which will take care of that - (You've tagged Javascript in your question so I assume you are open to Javascript solution)
var elm = document.querySelectorAll('ul li');
for (var i=0; i < elm.length; i++) {
elm[i].setAttribute("contenteditable", "true");
}
Demo (Assigning attribute using Javascript)
Just take a note over here, the selector am using in querySelectorAll()
is too general, will match ALL the ul
elements in your document, so if you want to make a specific group of li
elements editable, than assign a class
or an id
to your ul
element and appropriately define a unique selector.
If you want multiple ul
li
editable, it would be better to define a class
instead of an id
as id
has to be unique... So it would be cumbersome to define unique everytime you want a group of li
to be editable.
I had also same problem . So, I solved it by doing preventdefault() for backspace .Here I am getting all the Uls using querySelectorAll. For each ul I am checking the childrenLength i.e li tags and textContent. I am also checking for textcontent because otherwise user won't be able to delete any li when it is empty.
Based on this I am Disabling the Backspace. In this code I have done this for Muliple Uls
const allULList = document.querySelectorAll(".TaskList");
allULList.forEach((list) => {
list.addEventListener("keydown", (e) => {
const childrenLength = list.children.length;
const emptytext = list.textContent.trim().length;
if (emptytext === 0 && e.key === "Backspace" && childrenLength === 1) {
e.preventDefault();
}
});
});