Tips for contenteditables
September 13, 2022 [JavaScript, Programming]I've been working a bit with contenteditable tags in my HTML, and learnt a couple of things, so here they are.
Update: See also my demo of how to select text in various ways in a contenteditable.
Why can't I see the cursor inside an empty contenteditable?
If you make an editable div like this:
<div contenteditable="true"> </div>
and then try to focus it, then sometimes, in some browsers, you won't see a cursor.
You can fix it by adding a <br /> tag:
<div contenteditable="true">
<br />
</div>
Now you should get a cursor and be able to edit text inside.
Programmatically selecting text inside a contenteditable
It's quite tricky to get the browser to select anything. Here's a quick recipe for that:
<div id="ce" contenteditable="true">
Some text here
</div>
<script>
const ce = document.getElementById("ce");
const sel = document.getSelection();
self.setBaseAndExtent(ce.firstChild, 6, ce.lastChild, 10);
</script>
This selects characters 6 to before-10, i.e. the word "text". To select more complicated stuff inside tags etc. you need to find the actual DOM nodes to pass in to setStart and setEnd, which is quite tricky.
Whenever you setHTML on a contenteditable, add a BR tag
If you use setHTML on a contenteditable you should always append a <br /> on the end. It doesn't appear in any way, and it prevents weird problems.
Most notably, if you want to have an empty line at the end of your text, you need two <br /> tags, like this:
<div id="ce" contenteditable="true">
Some text here
</div>
<script>
const ce = document.getElementById("ce");
ce.innerHTML = "a<br /><br />"
</script>
If you only include one br tag, there will be no empty line at the end.
Selecting the end of a contenteditable
It's surprisingly tricky to put the cursor at the end of a contenteditable div but here is a recipe that works:
const range = document.createRange();
range.selectNodeContents(ce);
range.collapse();
const sel = document.getSelection();
sel.removeAllRanges();
sel.addRange(range);
(Where ce is our contenteditable div.)
NOTE: this won't work if you don't add a br tag at the end, as described above!
Update: beware of newlines in your source HTML
Note: not <br> tags, but actual newlines in your HTML source, can cause weird behaviour, especially around selections.
For example, if your div ends with a newline, you can't select the end of it by doing this:
const sel = document.getSelection(); sel.selectAllChildren(editor); sel.collapseToEnd();
The above will work (put your cursor at the end of the text) if there is no newline in the source, but not work (make your cursor disappear or jump to the right of the div) if there is a newline.
So if you're programmatically generating the HTML, I recommend removing this "extraneous" whitespace if you can.
More tips?
Any more tips? Drop them in the comments and I'll include them.