Search code examples
javascripthtmlcsstextarea

Resize textarea on input


I wanted to create a auto-growing textarea, so I used this guide. It works well, but there is a small problem. When you insert large texts and delete them, the textarea has a bigger size than it should have. With every inserted character, the size is reduced by 1-2 px, so with a few inserted characters the height is right again.

To recreate the worng scrollHeight, insert 'a \n b \n c \n d \n e' into the textarea.Now delete all of it. The textarea keeps a bigger size than it needs now. With every inserted character the textarea will adjust its size to the right value.

$("#message-box").on('input', function() {
  var scroll_height = $("#message-box").get(0).scrollHeight;
  $("#message-box").css('height', scroll_height + 'px');

  $("body > p").remove();
  $("body").append("<p>ScrollHeight: " + scroll_height + "</p>");
});
#message-box {
  resize: none;
  width: 400px;
  min-height: 20px;
  padding: 5px;
  overflow: hidden;
  box-sizing: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea id="message-box"></textarea>

Here is the example in CodePen

How can I get the textarea to resize to the smallest possible value immediately after a big text is deleted?


Solution

  • Using CSS

    Using the field-sizing: content; (See: browser availability)

    textarea {
      field-sizing: content;
      min-width: 10rem;
      min-height: 2rem;
    }
    <textarea></textarea>

    Using JavaScript

    Reset it quickly to auto before going for scrollHeight and reassagning it:

    const resizeOnType = (evt) => {
      const elTextarea = evt.currentTarget;
      elTextarea.style.height = "auto";
      elTextarea.style.height = `${elTextarea.scrollHeight}px`;
    };
    
    document.querySelectorAll(".resizeOnType").forEach(el => {
      el.addEventListener("input", resizeOnType);
    });
    #message-box {
      resize: none;
      width: 100%;
      box-sizing: border-box;
      padding: 5px;
      /* min-height: 100px; /* IF NEEDED, ADD SOME DESIRED MIN-HEIGHT */
    }
    <textarea class="resizeOnType" id="message-box"></textarea>

    which works on input Elements too