<h1>Auto-Growing <code>&lt;textarea></code></h1>

<form action="#0">

  <label for="text">Text:</label>
  <div class="grow-wrap">
    <textarea name="text" id="text" onInput="this.parentNode.dataset.replicatedValue = this.value"></textarea>
  </div>

</form>
.grow-wrap {
  /* easy way to plop the elements on top of each other and have them both sized based on the tallest one's height */
  display: grid;
}
.grow-wrap::after {
  /* Note the weird space! Needed to preventy jumpy behavior */
  content: attr(data-replicated-value) " ";

  /* This is how textarea text behaves */
  white-space: pre-wrap;

  /* Hidden from view, clicks, and screen readers */
  visibility: hidden;
}
.grow-wrap > textarea {
  /* You could leave this, but after a user resizes, then it ruins the auto sizing */
  resize: none;

  /* Firefox shows scrollbar on growth, you can hide like this. */
  overflow: hidden;
}
.grow-wrap > textarea,
.grow-wrap::after {
  /* Identical styling required!! */
  border: 1px solid black;
  padding: 0.5rem;
  font: inherit;

  /* Place on top of each other */
  grid-area: 1 / 1 / 2 / 2;
}

body {
  margin: 2rem;
  font: 1rem/1.4 system-ui, sans-serif;
}

label {
  display: block;
}
/*
  You COULD do this with external JavaScript, but it's so simple it works as a one-liner in the HTML as well.
*/

// const growers = document.querySelectorAll(".grow-wrap");

// growers.forEach((grower) => {
//   const textarea = grower.querySelector("textarea");
//   textarea.addEventListener("input", () => {
//     grower.dataset.replicatedValue = textarea.value;
//   });
// });

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.