'Random <b> tag being added to contentEditable div?

I'm cloning the chat post from Tumblr:

enter image description here

I'm using regex, range and getSelection() to wrap any text before the colon with a <span> element that bolds the interior font with css.

Consider this situation: I type Me:, the text is correctly wrapped and bolded. I backspace, watching everything be deleted in google chrome developer tools. Once the entire div is empty I try typing again and all of a sudden a <b> tag has been added and is now wrapping all the text. If I continue to type and type Me: again, the text will be wrapped by the span tag inside of this errant <b> tag.

I'd really appreciate any help on this. I'm about to throw my laptop out of the window. If you look at the code below I'm no longer creating any <b> tag. I was trying to create <b> tags previously and switched to <span>, so is there any possibility that some child has just never been cleared out of the relevant div? Beyond that I have no idea...

Here's the code:

const ChatPostInput = () => {

  const regexChat = () => {
    var chatDiv = document.querySelector('.chatText')
    console.log(chatDiv.childNodes)
    
    var regexBold = new RegExp(/^(.*?:)/, 'gm')

    if (window.getSelection) {
      var sel = window.getSelection(),
      suffixNode, bold = document.createElement('span') //here I'm creating the span element
      bold.setAttribute('class', 'boldText')
      var range = sel.getRangeAt(0)
      range.deleteContents()
      
      var text = range.commonAncestorContainer.textContent
      var matched = text.match(regexBold)

      if (matched) {
        bold.innerText = range.commonAncestorContainer.textContent
        range.commonAncestorContainer.textContent = '';
        range.insertNode(bold)
        range.setEndAfter(bold)
        range.collapse(false)
        range.insertNode((suffixNode = document.createTextNode(' ')))
        range.setStartAfter(suffixNode);
        sel.removeAllRanges();
        sel.addRange(range)
      }
    }
  }

  return (
    <div
      className='chatText'
      contentEditable={true}
      onInput={e => {
        //this is a hack to simply skip regexChat() when hitting backspace
        if (e.nativeEvent.data !== null) {
          regexChat()
        }
      }}
      
      onKeyDown={e => {
        e.stopPropagation();
        if (e.key === 'Enter') {
          if (window.getSelection) {
            var selection = window.getSelection(),
            range = selection.getRangeAt(0),
            br = document.createElement('br'),
            br2 = document.createElement('br'),
            suffixNode
            range.deleteContents();
            range.insertNode(br);
            range.collapse(false)
            range.insertNode(br2);
            range.setEndAfter(br2);
            range.collapse(false);
            range.insertNode((suffixNode = document.createTextNode(' ')));
            range.setStartAfter(suffixNode);
            selection.removeAllRanges();
            selection.addRange(range);
          }
        }
      }}
    >
    </div>
  )
}

UPDATE 1

I've just found a hacky fix where I override the value of the <b> tag to be font-weight: normal but I mean what in the actual !@$% is going on here? This hack will be fine for my purposes for now but if anyone could reproduce this issue I'd really appreciate it.



Solution 1:[1]

Handle the backspace in onKeyDown event.

If div is empty do the following:

const range = document.createRange()
range.selectNode(node);
range.setStart(node, 0);
range.setEnd(node, 0);

const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Chadjulian