StimulusJS Textarea autogrow
Standard <textarea>
does not autogrow while you add new rows:
Improved <textarea>
with autogrow:
CSS has "field-sizing: content"
, that lets you autogrow your text inputs.
TailwindCSS has field-sizing-content
.
But field-sizing
is not supported by all browsers.
So you do have to use JS instead.
After many iterations, here’s my perfected JS approach:
31.12.2024 version: #
// autogrow_controller.js
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static values = {
maxHeight: { type: Number, default: 15 },
};
connect() {
this.resize();
}
resize() {
const textarea = this.element;
textarea.style.height = "auto";
textarea.style.overflowY = "hidden";
// while textarea scrollHeight > textarea offsetHeight & textarea offsetHeight < this.maxHeightValue (5) rows * height of 1 row
while (
textarea.scrollHeight > textarea.offsetHeight &&
textarea.offsetHeight <
this.maxHeightValue * parseFloat(getComputedStyle(textarea).lineHeight)
) {
// increase height of textarea by one row
textarea.style.height = `${
textarea.offsetHeight +
parseFloat(getComputedStyle(textarea).lineHeight)
}px`;
}
// if textarea already has > maxHeight rows, activate scroll
if (
textarea.offsetHeight >=
this.maxHeightValue * parseFloat(getComputedStyle(textarea).lineHeight)
) {
textarea.style.overflowY = "auto";
}
}
}
14.06.2023 version: #
Just connect the below stimulus controller to a <textarea>
and you’re good to go!
rails g stimulus autogrow
StimulusJS controller inspired by MDN HTMLTextAreaElement example:
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
connect() {
this.element.style.overflow = "hidden";
this.grow();
}
grow() {
this.element.style.height = "auto";
this.element.style.height = `${this.element.scrollHeight}px`;
}
}
Usage with html.erb
:
<%= form.text_area :content,
# rows: 5,
data: { controller: 'autogrow',
action: "input->autogrow#grow" } %>
31.03.2022 version: #
// app/javascript/controllers/autogrow.js
import { Controller } from "@hotwired/stimulus";
// Connects to data-controller="autogrow"
// <%= form.text_area :content, data: {controller: "autogrow" } %>
// <textarea data-controller="autogrow" name="article[content]"></textarea>
export default class extends Controller {
initialize() {
this.autogrow = this.autogrow.bind(this);
}
connect() {
this.element.style.overflow = "hidden";
this.autogrow();
this.element.addEventListener("input", this.autogrow);
window.addEventListener("resize", this.autogrow);
}
disconnect() {
window.removeEventListener("resize", this.autogrow);
}
autogrow() {
this.element.style.height = "auto";
this.element.style.height = `${this.element.scrollHeight}px`;
}
}
This old version is based on the fantastic @guillaumebriday’s stimulus-textarea-autogrow
Did you like this article? Did it save you some time?