useRef で作る Auto Resize するテキストフィールド


本記事では、React Hooks のひとつである useRef を使った Auto Resize するテキストフィールドの実装例を紹介します。
Auto Resize とは入力された文字の量(高さ)に応じてテキストフィールドの高さを伸縮させることを指します。
デフォルトの <textarea> では、複数行入力して要素の高さを超えた場合、スクロールバーが表示され文章全体を見渡すことができなくなります。

ググっても実装例があまりなくライブラリを入れるほどでもないので参考になれば幸いです。

TL;DR

さっそく、コード例を紹介します。

CodeSandbox で実際に触ることもできます。

import { useEffect, useRef, useState } from "react";
import "./styles.css";

function useAutoResizeTextArea(value: string | undefined) {
  const ref = useRef<HTMLTextAreaElement>null;

  useEffect(() => {
    const element = ref.current;
    if (!element) {
      return;
    }

    const { borderTopWidth, borderBottomWidth, paddingTop, paddingBottom } =
      getComputedStyle(element);

    element.style.height = "auto";
    element.style.height = `calc(${element.scrollHeight}px + ${paddingTop} + ${paddingBottom} + ${borderTopWidth} + ${borderBottomWidth})`;
  }, [value]);

  return ref;
}

export default function App() {
  const [value, setValue] = useState("");
  const textAreaRef = useAutoResizeTextArea(value);

  return (
    <div className="App">
      <textarea
        style={{ resize: "none", boxSizing: "border-box" }}
        value={value}
        onChange={(e) => setValue(e.target.value)}
        ref={textAreaRef}
      />
    </div>
  );
}

簡単な解説

useAutoResizeTextArea() という Custom Hooks のなかで、参照した DOM (<textarea>) の高さを計算しています。

element.style.height = "auto";

行数が減ったときに縮むように、いったん “auto” を指定しています。

element.style.height = `calc(${element.scrollHeight}px + ${paddingTop} + ${paddingBottom} + ${borderTopWidth} + ${borderBottomWidth})`;

そして、各プロパティの合算を要素の高さに代入します。

style={{ resize: "none", boxSizing: "border-box" }}

スタイルについて、細かいですが入力すると高さがリセットされるのでドラッグでの resize は無効にしています。

また、最近の Reset CSS の傾向から boxSizing: "border-box" がデフォルトっぽいので指定しています( content-box 指定なら scrollHeight だけを代入で済むかも)。

さいごに

同様に useRef を使ったライブラリがあるので、より細かい設定がしたい場合は参考になると思います。

react-expanding-textarea

以上、この記事が誰かのお役に立てれば幸いです。

今すぐの転職でなくてもOKです!まずはお話しませんか?

現在弊社では一緒にお仕事をしてくださるエンジニアさんやデザイナーさんを積極募集しています。まずはカジュアルな面談で、お互いに大事にしていることをお話できたらうれしいです。詳しい応募要項は以下からチェックしてください。

パートナー契約へのお問い合わせもお仕事へのお問い合わせも、どちらもいつでも大歓迎です。まずはオンラインでの面談でお話しましょう。ぜひお気軽にお問い合わせください!

話をしてみたい!

投稿者 Gaji-Labo Staff

Gaji-Laboの社内デジタル環境でいろいろなお手伝いをしているがじ専務&じら常務。みんなのシリーズ記事をまとめたり、卒業したスタッフの過去記事を記録したり、Twitterをやったりしています。