Skip to content

Instantly share code, notes, and snippets.

@avk
Created July 22, 2021 13:30
Show Gist options
  • Save avk/a6cfff1a23fdb3c89f33ba0919477f7d to your computer and use it in GitHub Desktop.
Save avk/a6cfff1a23fdb3c89f33ba0919477f7d to your computer and use it in GitHub Desktop.
auto-resizing textareas in Stimulus 1.2
/* example use
<%= form.text_area :notes,
cols: "auto",
rows: "1",
placeholder: "+ thoughts",
data: {
controller: "autorow",
action: "input->autorow#handleInput",
target: "autorow.textarea",
}
%>
*/
import { Controller } from "stimulus"
export default class extends Controller {
static targets = [
'textarea',
]
initialize() {
// TODO read from markup, ideally via Stimulus 2 Values API
this.charsInLine = 30
this.maxRows = 10
}
handleInput() {
// console.debug(`should have at least ${this.calcRows()} rows`)
this.textareaTarget.setAttribute("rows", this.calcRows())
}
calcRows() {
// why? either input lines or line breaks can make more rows
const allRows = Math.max(this.countLines(), 1 + this.countLineBreaks())
// why? don't make too many rows
return (allRows > this.maxRows) ? this.maxRows : allRows
}
countLines() {
if (!this.hasTextareaTarget) {
return 1
}
const currentLength = this.textareaTarget.value.length
// why? round up if approaching next line
const lines = Math.ceil(currentLength / this.charsInLine)
// why? never less than 1 line
return (lines < 1) ? 1 : lines
}
countLineBreaks() {
if (!this.hasTextareaTarget) {
return 0
}
const lineBreaks = /\n/g
const matches = this.textareaTarget.value.match(lineBreaks)
return (matches) ? matches.length : 0
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment