JavaScriptで入力フォームにふきだしのようなツールチップを表示する例
入力フォームには既にplaceholderという属性があって、簡単な入力ヒントを表示することが出来ますが、今回はそれに加えて入力欄にフォーカスが移動した際に右側にふきだしのようなツールチップを表示する仕組みを作ってみたいと思います。
placeholderの例
表示サンプル
このように薄い色の文字で入力内容のヒント等を表示できますが、入力をはじめると消えてしまうし、あまり長い説明は書けないというデメリットもあります。
HTMLコード
<input type="text" placeholder="名前を入力してください">
入力フォームにふきだしツールチップを表示する例
INPUTタグやTEXTAREAタグの入力欄にフォーカスを合わせるとそれぞれのツールチップが表示されるのが確認できると思います。
HTMLの例
<form>
<div>
<input type="text" placeholder="ハンドル名">
<div class="tooltip">ハンドル名は4~20文字です</div>
</div>
<div>
<input type="text" placeholder="メールアドレス">
<div class="tooltip">確認できるメールアドレスを入力してください</div>
</div>
<div>
<textarea placeholder="問い合わせ内容"></textarea>
<div class="tooltip">2000文字まで入力可能です</div>
</div>
</form>
HTMLはかなりシンプルで、INPUTタグ等の入力パーツとツールチップ用のDIVタグをそれぞれ別のDIVタグで囲んでいるだけです。
入力欄とツールチップを紐付けるためにDIVタグで囲んでいますが、TABLEのTDだったり、DL/DDタグやUL/LIでも全然構いません。
CSSの例
<style>
form.div {
position:relative;
}
.tooltip:before {
content: '';
position:absolute;
top:10px;
left:-20px;
border:12px solid transparent;
border-right:12px solid #808080;
}
.tooltip {
position:absolute;
background-color:#808080;
color:white;
font-size:0.8em;
border-radius:0.5em;
padding:10px;
margin:-0.8em 0.5em 0 1em;
display:none;
}
input[type="text"],textarea {
width:10em;
}
</style>
CSSの部分は以前投稿した「CSSでLINE風のふきだしを出来るだけシンプルに作ってみる」のCSSをほとんど流用しただけですね。
角丸はborder-radiusで表現できるし、ふきだしの左向き三角形もtransparentを使ってCSSで描いています。
あと、ふきだしの表示位置を入力パーツと合わせるためにform.divにposition:relative;を指定し、tooltipにはposition:absolute;を指定して調整したくらいでしょうか。
JavaScriptの例
<script>
let elms = document.querySelectorAll('form input[type=text],form textarea');
for (let i = 0; i < elms.length; i++) {
elms[i].onfocus = function () {
let = tooltip = this.parentNode.querySelector('.tooltip');
tooltip.style.display = 'inline-block';
};
elms[i].onblur = function () {
let = tooltip = this.parentNode.querySelector('.tooltip');
tooltip.style.display = 'none';
}
}
</script>
特に難しいことはやっていませんが、querySelectorが便利なので、存分に活用している感じです。
let elms = document.querySelectorAll('form input[type=text],form textarea');
この1行だけで、formタグの下にあるinput type="text"の入力パーツ、およびtextareaを配列で取得出来てしまいます。
そして、それぞれのonfocusイベントにツールチップを表示するコード、onblurイベントで非表示にするコードを記述。
それぞれのtooltipにIDを付けるのも面倒だし、ツールチップを増やすたびにIDを書き換えなきゃならないのは保守性も悪くなりそうなので、ここでもquerySelectorを使ってtooltipを探しています。
let = tooltip = this.parentNode.querySelector('.tooltip');
thisはフォーカスがあたっている要素、つまりinputまたはtextareaです。
そのparentNode(親要素)の下にあるクラス名tooltipの要素を検出しているわけですね。
JavaScriptのnextSiblingを使って「inputタグの次の要素」という指定方法もアリといえばアリですが、nextSiblingってテキストノードも検出するんですよ。
なので、
<input type="text"><div class="tooltip">ほにゃらら</div>
と書いた場合はnextSiblingがtooltipになりますが、
<input type="text">
<div class="tooltip">ほにゃらら</div>
と改行を入れて書いた場合はinput要素の次は改行のテキストノードになってしまいます。
となると、nextSiblingをループさせて次に発見したdivを選択…みたいなコードを書かねばならず、だったら親要素からquerySelectorで.tooltip探したほうが早くね?と思ってそんなコードにしました。
まとめ
かつてツールチップといえばマウスをホバーした(上に載せる)ときに表示するのが一般的、というかWindowsアプリケーションでは今もそれが主流ですが、いまどきのWebページはPCとスマホの両方に対応するのが当たり前です。
そうなるとマウスホバーでツールチップの表示ってスマホでは全く意味のない機能になってしまうため、明示的にクリック(タップ)したときやフォーカスがあたったときにツールチップを表示しなきゃなーと、こんな作りにしてみました。