JavaScript: Auto-Resized <textarea> Element

Available on GitHub @ KnowledgeXFR/textarea-height-resizer

I created a JavaScript function that resizes the height of a <textarea> element whenever its content changed. Hoping this makes someone’s day a little brighter, and frees up their time to work on something more pressing.

The Function

The resizeTextareaHeight() function is written to allow it to be called both via an event, or manually. While its original purpose was to respond when the value of the <textarea> was changed, it was also important to have it called on load, after the initial value was set.

/**
 * Resize textarea height based on content
 *
 * @param {Element} element - The textarea element object
 *
 * @author Michael J. Bartholomew <www.knowledge-xfr.com>
 * @license MIT
 **/
function resizeTextareaHeight(element) {
  
  // Get computed style
  const cssObj = window.getComputedStyle(element, null);
  
  // Calculate padding/border height difference
  const computed_height = parseInt(cssObj.getPropertyValue('height'));
  const diff = computed_height - element.clientHeight;
  
  // Create temp textarea
  var temp = document.createElement('textarea');
  temp.style.position = 'absolute';
  temp.style.left = '100vw';
  temp.style.visibility = 'hidden';
  document.body.appendChild(temp);

  // Mirror textarea styles and value
  temp.style.width = element.clientWidth + 'px';
  temp.style.fontFamily = cssObj.getPropertyValue("font-family");
  temp.style.fontSize = cssObj.getPropertyValue("font-size");
  temp.style.lineHeight = cssObj.getPropertyValue("line-height");
  // Add additional styles when needed
  temp.value = element.value;
  
  // Calculate new height and apply if it doesn't equal element height
  temp.style.height = 0;
  var new_height = temp.scrollHeight + diff + 'px'
  if (element.style.height != new_height) {
    element.style.height = new_height;
  }
  
  // Remove temp textarea
  document.body.removeChild(temp);
  
}

How Does It Work?

I’ve commented the code above, but understand how further explanations are beneficial for those new to programming or languages. Below are the steps the function takes:

  1. Obtains the computed styles of the <textarea> element being passed as a parameter. These styles will be referenced in steps two and three.
  2. Calculates the padding and border height difference. This is important as the <textarea> element’s scrollHeight() method only considers the scrollable area inside of the element, while ignoring styles like top/bottom padding and borders.
  3. Creates a hidden, temporary copy of the <textarea> element being passed as a parameter. The example applies five different styles, but these can be customized and changed. In my case, I was using the element as an input for Markdown text, so I setup the font styles to reflect my needs.
  4. Calculates the required height, and if the new height doesn’t equal the existing height, then it updates it.
  5. Last, we perform some cleanup, removing the temporary <textarea> element from the page.

Why Create a Temporary <textarea> Element?

I initially wrote the logic to measure the element’s scroll height, and apply it to its height when it was different. It worked fine until I started deleting text, since the scroll height will never report as being less than the element’s own height.

I then tried to set the element’s height to 0 before calculating the required height. Unfortunately, that resulted in screen flickering, as I was changing the height twice in quick succession.

Creating a temporary copy of the element, performing calculations on that copy, and only updating the element’s height if needed solved these issues.

Using It

The two ways that I am using it today are by calling it manually upon initial value population, and then via the input event to listen for changes.

Call Manually

Assuming that the <textarea> element is defined via html:

<textarea id="editor"></textarea>

Manually calling the function is as simple as:

  1. Querying for the <textarea> element
  2. Passing the result as the parameter into the resizeTextareaHeight() function:
// Query for the <textarea> element
var el = document.querySelector('textarea#editor');

// Pass the element variable to the function
resizeTextareaHeight(el);

Call via an Event Listener

Assuming that the <textarea> element is defined via html:

<textarea id="editor"></textarea>

Simply:

  1. Query for the <textarea> element
  2. Add an EventListener to the result from step 1, passing the event’s target (e.target) as the parameter for the resizeTextareaHeight() function in the addEventListener’s listener parameter.
// Query for the <textarea> element
var el = document.querySelector('textarea#editor');

// Add "input" event listener
el.addEventListener('input', (e) => {
  resizeTextareaHeight(e.target);
});