3 ms·
The behavior for inserting text varies by browser and/or OS, unfortunately. I made [sandbox] to test this. Click the button to set the selection to the first po
by jitl 4y ago
The behavior for inserting text varies by browser and/or OS, unfortunately. I made [sandbox] to test this. Click the button to set the selection to the first position inside the first <strong> tag in the contenteditable div.
[sandbox]: https://codesandbox.io/s/gracious-dew-rx3xhz?file=/index.html https://codesandbox.io/s/gracious-dew-rx3xhz?file=/index.htm...
On my Mac, Firefox 104.0.2 inserts new characters inside the <strong>, so they're bold.
In Chrome, the browser API allows positioning the selection there, but during the input event, the selection ends up normalized to just before the strong tag, so the characters aren't inserted into the <strong> tag.
In Safari, the browser API accepts the arguments to set the selection to the first position inside the strong tag, but normalizes during the API call, and the selection always ends up right before the strong tag.
The variance of contentEditable is a huge impediment to using the API raw. If you want reliable, relatively low-level control of rich text input on the web, use ProseMirror.
(I learned a lot about this stuff while working on Notion's rich-text editor, which is all custom.)
- panzerboiler 4y agoThank you for the example. I do mostly the same thing and as a Safari user there is no way to place the caret in "the right spot". What I found working (but I still have to test on other browsers and make my mind if it is really worth the hack) is to place a dummy marker with [contenteditable="false"] at the beginning and the end of the inline elements (the one on the end has to be skipped to avoid getting stuck in a limbo inside the parent element). This way the result is similar to the one in Bike, with the caret that stops on both sides of the element. Let's see if this thing goes somewhere...
- jitl 4y agoOf of the top of my head, you'll need to watch out for: - The default behavior that triple-click to selects a whole paragraph/line will stop at the first contenteditable=false element. - Android may dismiss the keyboard & selection if the selection ever touches one of your contenteditable=false marker elements. - Firefox won't let you place the caret in between two contenteditable=false elements, or at the start or end of a contenteditable=true element if the first/last child is contenteditable=false. Why not use ProseMirror?
- panzerboiler 4y agoI am sure that there are plenty more! Working on top of customeditable is hell, but it is the price to pay if you want to implement a custom editing experience. Of the issues you listed, the triple-click is a good one, and easy to solve with a custom handler (even if there is no tripleclick event, the detail property of the event object holds the number of consecutive clicks). I am pretty sure that ProseMirror does something similar, because it uses [contenteditable="false"] decorations without interfering with the triple-click selection. For mobile devices and Firefox I would surrender, and gracefully degrade the editing experience. Why not use ProseMirror? It doesn't fix this issue, does it? At least in the demos on their website you cannot insert text at the beginning of a styled element. You cannot do it even in a native application (at least on macOS) without a custom handling of the selection.
- lewisjoe 4y agoThanks for the sandbox. I'm working on a company-wide blog post on a good richtext editing strategy / library and wanted to demostrate how unpredictable it is with contenteditable. This sample is perfect and I'm thinking of hyperlinking the sandbox :) Do you happen to have any more samples to demonstrate how difficult it is to work with contenteditable APIs?
- jitl 4y agoOh, I made that sandbox for my HN comment. I actually have a similar internal blog post & several more complex examples I built for that, but can't share any of it publicly.