How to make a textarea that dynamically adjusts size based on amount of text inputted (using pure JavaScript, without jQuery)

As a server-side developer, I am venturing into the world of vanilla JS to expand my skillset.

My current challenge involves creating a form where textareas are initially hidden behind button clicks and resize as more text is entered. This task is pushing the boundaries of my expertise, but I'm determined to tackle it on my own for learning purposes.


Here's my progress so far.

Picture a forum where users post content with a "reply" button underneath. Clicking this button reveals a basic textarea for typing responses. Here's the simple JavaScript code I used:

var replyBtns = document.querySelectorAll('[id=rep]');

for(var i = 0; i < replyBtns.length; i++) {
 replyBtns[i].addEventListener('click', function(e) {
   e.preventDefault();
   var textarea = document.getElementById("reply-message");
   if (textarea) { textarea.parentNode.removeChild(textarea); }
   var replyBox = document.createElement('textarea');
    replyBox.setAttribute('id', 'reply-message');
    replyBox.setAttribute('placeholder', 'Reply');
   this.parentNode.insertAdjacentElement('beforeend', replyBox);
 }, false);
}

This JavaScript snippet creates a text area in the HTML, paired with the following CSS:

textarea#reply-message {
  display: block;
  border: none;
  color:#306654;
  font-size:120%;
  padding: 5px 10px;
  line-height: 20px;
  width:550px;
  height: 20px;
  border-radius: 6px;
  overflow: hidden;
  resize: none;
}

The system works smoothly.


Moving forward, my next goal was to make the textarea resize dynamically as the text surpasses its initial size. To achieve this, I followed these steps:

  • Retrieve the content within the textarea

  • Create an invisible clone div

  • Style the clone to mimic the textarea's dimensions and typography

  • Copy the content into the clone

  • Determine the height of the clone

  • Adjust the height of the textarea accordingly

This approach capitalizes on a div element's inherent ability to expand based on its content height. Credit goes to this blog post for enlightening me on this technique.

Below is the JavaScript implementation of the aforementioned method:

let txt = document.getElementById('reply-message'),
    hiddenDiv = document.createElement('div'),
    content = null;

hiddenDiv.classList.add('hiddendiv');

document.body.appendChild(hiddenDiv);

txt.addEventListener('keyup', function () {

  content = this.value;
  hiddenDiv.innerHTML = content + '\n\n';
  this.style.height = hiddenDiv.getBoundingClientRect().height + 'px';

}, false);

Define hiddendiv as follows:

.hiddendiv {
  position: absolute;
  left: -9999px;
  visibility: hidden;
  white-space: pre-wrap;
  width: 550px;
  height: 20px;
  font-size: 120%;
  padding: 5px 10px;
  word-wrap: break-word;
  overflow-wrap: break-word;
}

However, I need to ensure that this JavaScript snippet only executes once the textarea actually exists.

Currently, it runs upon page load, without any impact since textareas have not yet been created. How can I make sure it activates only after their creation? As a novice in JavaScript, I'm struggling with this concept. Any guidance would be greatly appreciated.

Answer №1

Although not directly addressing your query, consider restructuring your code for similar outcomes.

Ensure to attach the event listener to your textarea during its creation process before incorporation into the page.

Incorporate code resembling this in your initial segment of JavaScript:

replyBox.setAttribute('placeholder', 'Reply');
replyBox.addEventListener('keyup', function () {
    /* implement event handling here */
}, false);

An alternative method for managing these tasks would involve transferring all actions related to configuring your textareas to a distinct function.

function setUpReplyBox(replyBox) {
    replyBox.setAttribute('id', 'reply-message');
    replyBox.setAttribute('placeholder', 'Reply');

    hiddendiv.createElement('div');
    content = null;

    hiddendiv.classList.add('hiddendiv');
    document.body.appendChild(hiddenDiv);

    replyBox.addEventListener('keyup', function () {
        content = this.value;
        hiddenDiv.innerHTML = content + '\n\n';
        this.style.height = hiddenDiv.getBoundingClientRect().height + 'px';
    }, false);
}

Invoke this function right after producing the item at

var replyBox = document.createElement('textarea');
setUpReplyBox(replyBox);
this.parentNode.insertAdjacentElement('beforeend', replyBox);

Answer №3

Consider the possibility of using a div element with contenteditable attribute instead of a textarea, which may simplify your tasks.

#editor {
    -moz-appearance: textfield-multiline;
    -webkit-appearance: textarea;
    border: 1px solid gray;
    padding: 2px;
    width: 400px;
}
<div id="editor" contenteditable>this is an editable div</div>

Answer №4

Have you heard about the autosize plugin? You can find it here

To understand how to use it, check out the source code on github.

If your code works on page load but not during text updates, make sure to call your resize function on keyup, resize, and input events.

window.addEventListener('resize', yourFunc);
textarea.addEventListener('paste', yourFunc);
textarea.addEventListener('keyup', yourFunc);

You can also follow a simpler method explained here

function auto_grow(element) {
    element.style.height = "5px";
    element.style.height = (element.scrollHeight)+"px";
}
textarea {
    resize: none;
    overflow: hidden;
    min-height: 50px;
}
<textarea onkeyup="auto_grow(this)"></textarea>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieve the most recent tweet from a user's timeline using the twit npm package

I need help setting up a discord bot to send notifications for new tweets. Currently, I've implemented T.stream('statuses/filter', { follow : ['798934987978510337'] });, but it's also displaying mentions. Is there a way to o ...

Scrolling does not function properly on Android devices when utilizing skrollr.js in conjunction with multiple div elements containing the id "skrollr-body."

Having trouble with the scroll functionality in my skrollr.js animations. Everything works fine on desktop, but when I checked the rendered HTML in the browser console, I noticed that there are two divs with the same id "skrollr-body". One is empty and the ...

Ways to access information received from AngularJS in a different Javascript file

I am currently using Angular to retrieve output from a controller and display it using ng-bind. However, I have another separate JavaScript file that needs to utilize a value returned from Angular. In the example code provided below, the TestAppCtrl is ca ...

WebGL annotations failing to display on the webpage

I'm currently working on displaying a 3D model using Three.js in a web browser and looking to incorporate annotations like the ones shown in this Sketchfab model: Interactive 3D Test. I came across a helpful guide at this link, but I'm facing iss ...

Can we use an open-ended peer version dependency in package.json?

Question Summary Is it necessary for me to specify the peer dependency of @angular/core in my package.json file for a package containing easing functions that work with any version of Angular? "peerDependencies": { "@angular/core": "x.x" } Context I ...

What is the best way to extract information from a dynamically generated input field using vanilla JavaScript?

Creating a dynamic input field inside the 'education-field' div is the main goal here. The user can add more fields by clicking the "Add more" button, and the data from these input fields is crucial for form validation purposes. Users can input t ...

Image not yet clicked on the first try

I am encountering an issue with my image gallery. Currently, when I click on a thumbnail, the large image is displayed. However, I would like the first image to show up without requiring the user to click on its thumbnail. How can I address this problem? B ...

Testing of AngularJS Controller using Jasmine and Karma: "Error - Unable to read property 'then' of undefined"

I am currently attempting to perform unit testing on an AngularJS controller and encountering an error message while running Karma: Cannot read property 'then' of undefined I am unsure of what I am doing incorrectly. This is my first time con ...

Solution: The issue where the children's onChange event was not updating the parent in Ant Design was discovered to be due to the Select and Table components nested inside a Tab not changing according to the pageSize

I'm facing an issue with updating a parent element when the children's onChange event is triggered. Specifically, I have an Ant Design Select and Table inside a Tab that are not reflecting changes in the pageSize value. Although setPageSize func ...

The code is slicing data, but the changes are not reflecting in the user interface

Initially, there are three drop down menus displayed. Upon selecting an option from the first drop down menu, the values in the second drop down menu load. After selecting an option from the second drop down menu, a new set of drop downs appears. However, ...

Effortless Scrollspy with a custom Navigation Component, no Bootstrap needed

In my Table of Contents, identified as #TableOfContents, each href points to either an h2 or h3 tag. The issue I'm facing is that when the heading (h2 or h3) is observed by the intersection observer, the corresponding link in #TableOfContents is high ...

Identifying issues in jQuery code - What could be causing this error?

My jQuery code is not responding at all, not even showing an error! I'm not sure why, but here is the jQuery Code I'm using: /* This part is working fine */ $(".add-blog .blog-add-form .add-article .input-group select").on("change", function() ...

Creating a mock AJAX response using JSFiddle and jQuery

Is there a way to simulate an ajax response in jsfiddle? The documentation at mentions using new Request.HTML, but it seems to only work with Mootools. When I tried using jQuery, I got an error saying "ReferenceError: Request is not defined". In the examp ...

having difficulty transmitting parameter to angular directive

After assigning a collection to a source variable, I am trying to activate a third party control (bootstrap-select) using a directive that watches the assigned collection. angular .module('app').directive('bootstrapDropdown', ['$t ...

What is the best method for transferring data from the first table to the second table in Angular?

I am looking to transfer data (Item and Price) from the first table to the second table and increase the Quantity field in the Second table upon clicking on an Item in the First Table. I am currently developing in Angular 9. First Table: Code | Item | Pr ...

How can one determine when an animation in Three.js has reached its conclusion?

When I write code like this: function renderuj(){ scene.renderer.setClearColor(0xeeeeee, 1); ob1.animation.update(0.5); ob2.animation.update(0.5); scene.renderer.render(scene.scene, scene.camera); animationFram = reques ...

Implementing the row delete function in MUI DataGrid using JavaScript

My grid has a delete icon button in each row, but it's not deleting the row. Can someone please help me with this issue? I'm working on a todo app where each row should have its own delete button. I'm struggling to connect the deleteTodo co ...

Hover-over functionality not functioning properly on select images

My website, located at , is fully functional. When you visit the homepage, you will see some words that turn black when you hover over them. I recently switched this site, which was originally created in Dreamweaver, to Umbraco, a .net based CMS. My site ...

The Javascript function will keep on executing long after it has been invoked

I am currently facing an issue with calling a JavaScript function within an AJAX call. The progress function below is supposed to be executed every time the for loop runs. However, the problem is that although progress is being run as many times as the for ...

Ways to set a timeout for a hyperlink?

I have implemented two functions on the same element. One is AJAX for saving an image and the other is prettyPhoto ajax for displaying that image. Here is an example: This is the event > <a rel="prettyPhoto[ajax]" onClick="return false" > onMous ...