🐥

テキストエリア要素の高さ(height)を入力値に応じて動的に変更したい

2024/08/25に公開

概要

テキストエリア要素の height をさっと動的に変更したい。
ライブラリの使用 ver. は以下のとおりです。
react: v18
next: v14.2.5

方法

以下の hook を作成し、使用します。
hook の内容と使い方は後述のとおりです。

import { useCallback, useRef } from 'react';

type UseAutoResizeTextareaProps = { defaultHeight: number; maxHeight: number };
export const useAutoResizeTextarea = ({ defaultHeight, maxHeight }: UseAutoResizeTextareaProps) => {
  const textAreaRef = useRef<HTMLTextAreaElement>(null);

  const onChangeTextArea = useCallback(() => {
    if (textAreaRef.current) {
      // 元に戻した場合など、文字数が減少した場合に高さを合わせる
      textAreaRef.current.style.height = 'auto';
      if (textAreaRef.current.scrollHeight <= defaultHeight) {
        textAreaRef.current.style.height = `${defaultHeight}px`;

        return;
      }
      if (textAreaRef.current.scrollHeight >= maxHeight) {
        textAreaRef.current.style.height = `${maxHeight}px`;

        return;
      }
      textAreaRef.current.style.height = `${textAreaRef.current.scrollHeight}px`;
    }
  }, [defaultHeight, maxHeight]);

  return { textAreaRef, onChangeTextArea };
};

hook について

前提、scrollHeight の値を用いています。
→非表示の入力値も含めたテキストエリア要素の高さを表す数値です。
参考mdn に詳細な記述がありますのでご覧ください。

ざっくり処理内容

heightauto に変更し、表示領域の文字の高さを設定する共通処理の後に、
指定のテキストエリア要素の height の最小値、最大値と、 scrollHeight の値とを比較した結果に応じた処理を行います。

  1. scrollHeight が指定された最小値の高さより高いかつ、指定された最大値未満だった場合
    • scrollHeight > 最小値 かつ scrollHeight < 最大値
  2. scrollHeight が指定された最小値以下だった場合
  3. scrollHeight が指定された最大値以上だった場合

以下、比較した結果に応じた処理です。

  1. scrollHeight が指定された最小値の高さより高いかつ、指定された最大値未満だった場合
    • テキストエリア要素の heightscrollHeight の値を入れる。
  2. scrollHeight が指定された最小値以下だった場合
    • テキストエリア要素の height に指定された最小値を入れる。
  3. scrollHeight が指定された最大値以上だった場合
    • テキストエリア要素の height に指定された最大値を入れる。

hook の使い方

  1. hook を呼び出し、引数に以下の値を入れます。
    • defaultHeight:テキストエリア要素の最小の height の px 数値。
    • maxHeight:テキストエリア要素の最大の height の px 数値。

以下、呼び出しイメージです。

const { textAreaRef, onChangeTextArea } = useAutoResizeTextarea({ defaultHeight: 120, maxHeight: 720 });
  1. textAreaRefonChangeTextArea をテキストエリア要素に適用します。

以下、適用イメージです。

<textarea
  className="box-border h-[120px] w-full resize-none appearance-none py-[12px] text-[20px] leading-[24px] outline-none"
  name="post-text-area"
  onChange={onChangeTextArea}
  ref={textAreaRef}
/>

あとがき

個人開発などで、ライブラリを使いたくないときに役立てば幸いです。
最後までご覧いただきありがとうございました!

参考

https://techblog.gmo-ap.jp/2022/12/12/textarea_input_change/
https://developer.mozilla.org/en/docs/Web/API/Element/scrollHeight

Discussion