Text selection and replacement not working properly in textarea

I’m trying to make buttons for formatting (like making bold, italic etc) the selected text (md and/or html) of textarea tag using JavaScript.

Sometimes it works and sometimes it doesn’t without giving any error.

Code link https://jsfiddle.net/3gn75zLb

JS Code

function formatText(style) {
    var textarea_editor = document.getElementById('md-code');

    //get Selection
    var index_start = textarea_editor.selectionStart;
    var index_end = textarea_editor.selectionEnd;
    var text = textarea_editor.value;
    var selectedText = text.substring(index_start, index_end);
    var formatedText = selectedText;

    
        //format
        switch(style.toLowerCase()) {
            case 'b':
                var formatedText = "**"+selectedText+"**";
                break;

            case 'i':
                var formatedText = "*"+selectedText+"*";
                break;

            case 'u':
                var formatedText = "<u>"+selectedText+"</u>";
                break;

            case 'sup':
                var formatedText = "<sup>"+selectedText+"</sup>";
                break;

            case 'sub':
                var formatedText = "<sub>"+selectedText+"</sub>";
                break;

            case 'img':
                var formatedText = "![]("+selectedText+")";
                break;

            default:
                var formatedText = selectedText;
                break;
        }

        textarea_editor.innerHTML = text.substring(0, index_start)+formatedText+text.substring(index_end, text.length);
    }

There are click events associated with buttons to call the formatText() function

Like

formatText(‘b’) to enclose the selected text with ** to make it bold in markdown.

Questions

  • Is there any problem with the code?
  • Is there any better/easy way to do this using jQuery or anything else?

Answer

The problem is that you’re setting the innerHTML of the textarea, you need to set value property of the text area.

innerHTML with text area can only be used to set the initial content of the text area but as soon as you type something in the textarea, innerHTML won’t do anything, you need to then use the value property.

Also, currently if no text is selected even then the code adds styles, you can simply return from the function if the selectedText is empty.

See the code below:

function formatText(style) {
  var textarea_editor = document.getElementById('md-code');
  
  //get Selection
  var index_start = textarea_editor.selectionStart;
  var index_end = textarea_editor.selectionEnd;
  var text = textarea_editor.value;
  var selectedText = text.substring(index_start, index_end);
  var formatedText = selectedText;
  
  if (!selectedText) return;
  
  //format
  switch (style.toLowerCase()) {
    case 'b':
      var formatedText = "**" + selectedText + "**";
      break;

    case 'i':
      var formatedText = "*" + selectedText + "*";
      break;

    case 'u':
      var formatedText = "<u>" + selectedText + "</u>";
      break;

    case 'sup':
      var formatedText = "<sup>" + selectedText + "</sup>";
      break;

    case 'sub':
      var formatedText = "<sub>" + selectedText + "</sub>";
      break;

    case 'img':
      var formatedText = "![](" + selectedText + ")";
      break;

    default:
      var formatedText = selectedText;
      break;
  }

  textarea_editor.value = text.substring(0, index_start) + formatedText + text.substring(index_end, text.length);
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">

<div class="jumbotron bg-white px-2 py-0 m-0">
  <div class="my-2">
    <button type="button" class="btn btn-outline-secondary" onclick="formatText('b')"><b>B</b></button>
    <button type="button" class="btn btn-outline-secondary" onclick="formatText('i')"><i>I</i></button>
    <button type="button" class="btn btn-outline-secondary" onclick="formatText('u')"><u>U</u></button>
    <button type="button" class="btn btn-outline-secondary" onclick="formatText('sup')">T<sup>abc</sup></button>
    <button type="button" class="btn btn-outline-secondary" onclick="formatText('sub')">T<sub>abc</sub></button>
    <button type="button" class="btn btn-outline-secondary" onclick="formatText('img')">Img</button>
  </div>
  <textarea id="md-code" class="form-control" rows="20" name="note_content" placeholder="Markdown and/or HTML text"></textarea>
</div>