textareaの高さを自動調整する仕組みをNuxt.jsアプリに実装してみる

入力されているテキストの行数に応じて、textareaの高さが自動調整される仕組みです。改行を入力したり折り返しが発生するたびにリアルタイムに高さが変化します。

CSSだけで高さ調整をしており、JavaScriptはほとんど使いません。

HTMLソースは以下の通りです。

<template>
  <div class="flexible-textarea-wrapper">
    <!-- 次の行の `{ { message + "\n" } }` の記述の前後で改行してはいけない -->
    <div id="flexible-textarea">{{message + "\n"}}<textarea v-model="message"></textarea></div>
  </div>
</template>

ポイント

  • textareaの高さをCSSで100%にし、その外側のdivと同じ高さにする
  • textareaで編集中のテキストを、その外側のdivにもそのままテキストで表示する
  • divのテキストはdivの高さを自動調整する働きを持つが、同じ大きさのtextareaで上から隠され、textareaのみが見える状態とする

message はdataで与えておきます。

<script>
export default {
  data() {
    return {
      message: "Hello, World!",
    };
  },
}
</script>

CSSは以下のようにします。

<style>
/* これは高さ自動調整にとって重要ではない */
.flexible-textarea-wrapper {
  margin-left: auto;
  margin-right: auto;
  width: 400px;
}

/* ここからが高さ自動調整に必要 */
#flexible-textarea {
  position: relative;
  width: 100%;
  min-height: 32px;
  box-sizing: border-box;
  border: 0;
  padding: 5px; /* 下のtextareaのborder+paddingと同じ幅にする */
  text-align: left;
  white-space: pre-wrap; /* 改行や連続した空白を表示に反映 */
  font-size: 16px;
}

#flexible-textarea textarea {
  position: absolute; /* 外側のdivのテキストにかぶせるように表示 */
  left: 0;
  top: 0;
  width: 100%; /* 外側のdivと同じ大きさ */
  height: 100%;
  box-sizing: border-box;
  border: 1px solid #cccccc;
  border-radius: 6px;
  padding: 4px;
  outline: none;
  resize: none; /* 右下のリサイズのUI表示を非表示に */
  overflow: hidden; /* スクロールバーを非表示に */
  text-align: inherit;
  font-family: inherit; /* 外側のdivと同じフォントで表示 */
  font-size: inherit;
}
</style>