An alternative to contenteditable is to use a plain <textarea>, measure the inline width of the rendered text to get the absolute position of each word, and then overlay styles on top.
You need to debounce/throttle the change event handler to not fire too many re renders when typing.
You need to debounce/throttle the change event handler to not fire too many re renders when typing.
I used this approach for https://bigwav.app for highlighting text.
You can click the demo .bigwav file to take a look.