textareaは高さがrowsで指定した値になり自動でリサイズしてくれません。
今回は自動でリサイズする方法をまとめます。
こんなの
React
textarea.tsx
import { useEffect, useRef, useState } from 'react'
const heightToNumber = (str: string): number => {
return +str.replace('px', '')
}
const calculateRows = (textarea: HTMLTextAreaElement | null): number => {
if (!textarea) return 0
const style = getComputedStyle(textarea)
const lineHeight = heightToNumber(style.lineHeight)
const paddingY = heightToNumber(style.paddingTop) + heightToNumber(style.paddingBottom)
const textareaHeight = textarea.scrollHeight
return Math.floor((textareaHeight - paddingY) / lineHeight)
}
function TextAreaWithDynamicRows() {
const textareaRef = useRef<HTMLTextAreaElement | null>(null)
const [rows, setRows] = useState(0)
useEffect(() => {
setRows(calculateRows(textareaRef.current))
}, [])
const handleInput = (): void => {
setRows(calculateRows(textareaRef.current))
}
return (
<textarea ref={textareaRef} rows={rows} onInput={handleInput}>
あいうえお
</textarea>
)
}
解説
- textareaからパラメータを取得するのでrefで管理します
- textareaからgetComputedStyleでstyleを取得し
scrollHeight(コンテンツのスクロールを加味した高さ)からpaddingの分を引いてコンテンツの高さを出し、lineheightで割ることでrowsを求めることができます。
\n
を数えて行数を取得する例は多く見られますが、文字数により改行になっているものを数えることができないので今回は使っていません。
issue
なぜか1文字でも2行表示されるので解決法ある or もっと良いアルゴリズムあれば教えてください