HotwireでBootstrapのツールチップ使う

社内システムの開発と運用保守を行っている HaraShoです。

去年の夏頃にrails 7に上げてからHotwireを使って開発を行っています。
これまでフロントの実装はjQueryを使っていましたが、Hotwire導入後は極力jsを書かないようにし、Turbo FrameやTurbo Streamを使って画面描画しています。

ちなみに書いているコードより削除したコードの方が多いです 笑

さて本題なのですが、jQueryからHotwire(Stimulus)移行時に色々細かい問題が発生したのですが、その内の1つにBootstrapのツールチップが意図通り動作しない問題がありました。

これまでは以下のように記述していました。

import * as bootstrap from "bootstrap"

document.addEventListener("DOMContentLoaded", function() {
  const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
  const tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
    return new bootstrap.Tooltip(tooltipTriggerEl);
  });
});

ページ遷移する実装だと上記で良かったのですが、Hotwire、Turboによる遷移だと DOMContentLoadedは発生しません。
Turbo Frame等で部分的に置き換えた中にツールチップを表示したい要素が含まれていても bootstrap.Tooltipが割当たらない。

結論、こうしました。
tooltip_controller.js

import { Controller } from "@hotwired/stimulus"
import * as bootstrap from "bootstrap"

export default class extends Controller {
  initialize() {
    this.tooltip = null;
  }

  connect() {
    this.tooltip = new bootstrap.Tooltip(this.element);
  }

  disconnect() {
    this.tooltip.hide();
  }
}

ツールチップを表示したい要素に data-controller="tooltip"を設定します。
初期実装では disconnect() は実装していなかったのですが、ツールチップが表示されているタイミングで表示元の要素が置き換わるとツールチップが表示され続ける不具合があったので、disconnect()のタイングで消すようにしました。

Hotwire移行 & jQuery撲滅を初めてもうすぐ1年、8割ぐらいの画面はHotwireに移行できました。
上記のような細かい修正は必要ですが、個人的にHotwire移行は少ないリソースでの開発において適当だったと思います。

では、また。