input, textarea中のキャレット座標 (カーソルの位置) を取得する

この記事は GMOアドマーケティング Advent Calendar 2023 22日目の記事です。

お疲れ様です。GMOアドマーケティングの天河です。

テキストエリアなどの入力系のタグ内のテキストを選択した際に、その部分の座標情報を取得する方法を共有したいと思います(なかなか情報がなく苦戦した)。
ちなみに現時点で一発で取得できるメソッドは存在しません。ライブラリなどを利用する必要があります。

ちなみにこれができると、Twitter(現 X)や Instagram などのSNSでよく見るハッシュタグの予測変換機能が作れます。

HTML内で選択したDOM要素の情報は


によって、Range オブジェクトとして取得することが可能です。ここで取得した Range オブジェクト情報から

selectedText.getRangeAt(0).getBoundingClientRect()

で、選択した箇所の座標情報を取得することができます。

しかし、input タグや textarea タグの中のテキストを選択しても同じように Range オブジェクト情報は取得できません。空のオブジェクトが返却されてしまいます。
input タグや textarea タグではこの Range 情報を取得するメソッドはありません。

※ しかし input , textarea タグ内のテキストに選択範囲を設定するメソッドはなぜかある
HTMLInputElement: setSelectionRange() method

この入力系DOM内の座標情報を取得するためにはどのような手順を踏めばよいでしょうか。

実装のコード

実装の手順

大まかな手順は以下の通りです。

  • 選択したテキストの input , textarea タグと似たスタイルを持つ、仮の div タグを生成する
  • カーソル位置までの文字を取得して、仮の div タグの textContent に挿入する 
  • 仮の span タグを生成して、カーソル位置以降の文字を textContent に挿入する。
  • 仮の span タグを、仮の div タグに append する
  • 仮の div タグを DOM に挿入する
  • 仮の span タグの座標情報を取得する
  • 仮の div タグを削除する

実装の詳細

  • 選択したテキストの input , textarea タグと似たスタイルを持つ、仮の div タグを生成する

input タグと textarea タグ自体の座標情報は取れるので、offsetLeftoffsetTop の情報(つまり左上の座標)の情報を取得します。
そしてダミーの div タグを用意して、入力系タグのスタイルを全部コピーします。ページ全体におけるカーソル座標を取得するので、入力/テキストエリアの位置も考慮する必要があります。
最後に fixed を適応し、div タグを左上の位置に固定しておきます。

  • キャレット位置までの文字を取得して、仮の div タグの textContent に挿入する 

input タグ内の場合、空白文字も一緒にそのままダミータグに突っ込むと正しく座標が取得できないので何かの文字で置き換える必要があります。

  • 仮の span タグを生成して、キャレット位置以降の文字を textContent に挿入する。
  • 仮の span タグを、仮の div タグに append する
  • 仮の div タグを DOM に挿入する
  • 仮の span タグの座標情報を取得する
  • 仮の div タグを削除する

body にダミー要素を挿入することで、ページ内におけるDOMの座標を取得することができます。
こうして取得した座標を使って様々なUIを実現することが可能です。

例えば、選択箇所の近くにマーカーを表示させることができます。座標を計算して、付近にUIを表示するといった流れです。

See the Pen SelectionMarker by 10K (@10JII_K) on CodePen.

そのほかにも冒頭で述べたハッシュタグ機能も作ることができます。

See the Pen HashTag by 10K (@10JII_K) on CodePen.

おわりに

結構めんどくさいので、ライブラリで実現するのがいいかもしれませんね。本末転倒ですが。
お役に立てられたら幸いです。お役に立ったら、はてブお願いします(おねだり)

 

明日は @thomi40 さんによる「Notion APIでYouTubeやVimeoの動画を埋め込む方法」です。
引き続き、GMOアドマーケティング Advent Calendar 2023 をお楽しみください!  


■エンジニア採用ページはこちら!
https://recruit.gmo-ap.jp/

■GMOアドパートナーズ 公式noteはこちら!
https://note.gmo-ap.jp/