Tippy.js
Webシステムのツールチップって重要ですよね。
ボタンがあったとき、ツールチップがあると、押すとどんなことが起こるのか、ユーザーに分かりやすく知らせることができます。
また表示されているデータにどんな意味があるのか、Tipsを表示するのにもよいですね。
今回は気になるライブラリ【Tippy.js】を教えてもらったので、試してみようという記事です。
想定する読者
ウェブシステムの開発者を想定しています。
Cybozu社のkintoneのカスタマイズ開発者向けにも、少しだけコードを紹介します。
CDNで簡単に試してみる
Tippy.jsには、CDNが公開されていますので、 HTMLファイル一枚で試すことができます。
<html>
<head>
<title>TippyCDNExample</title>
<script src="https://unpkg.com/@popperjs/core@2"></script>
<script src="https://unpkg.com/tippy.js@6"></script>
</head>
<body>
<div style="display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; margin: auto;"
id="root">
<div>
<p>
これはCDN経由でTippy.jsを使用する例です。下のscriptタグで必要なライブラリを読み込み、<br/>
`tippy()`関数を使ってツールチップを作成できます。
</p>
<button id="myButton">My button</button>
</div>
<hr>
<div>
<p>`tippy()`関数を利用する以外にも、data-tippy-content属性を利用することもできます。</p>
<button data-tippy-content="My button with data attribute">My button with data attribute</button>
</div>
<hr>
<script>
// With the above scripts loaded, you can call `tippy()` with a CSS
// selector and a `content` prop:
tippy('#myButton', {
content: 'My tooltip!',
});
tippy("button");
const button = document.createElement('button');
button.textContent = 'New Button';
const root = document.querySelector('div#root');
if (root) {
root.appendChild(button);
} else {
console.warn('No root element found to append the button.');
}
tippy(button, {
content: `
<p>この例では、JavaScriptで新しいボタンを作成し、ツールチップを追加しています。</p>
<p>ボタンにマウスオーバーすると、このツールチップが表示されます。</p>
<p>ツールチップの内容はHTMLとして記述できます。</p>
<p>このように、Tippy.jsを使うことで、動的にツールチップを追加することができます。</p>
<p>さらに、ツールチップのスタイルや動作をカスタマイズすることも可能です。</p>
`,
allowHTML: true,
});
</script>
</div>
</body>
</html>
実際に動かすとこのようになります。

ボタンに触れるとツールチップが表示されることがわかると思います。
<script src="https://unpkg.com/@popperjs/core@2"></script>
<script src="https://unpkg.com/tippy.js@6"></script>
CDNからの利用ではpopper.jsと一緒に利用されていますね。
data-tippy-contentのようなカスタム属性を利用することもでき、タグに表記することでマークアップとしての可読性を高めることができます。
モジュールバンドラでの利用
モジュールバンドラからTippy.jsを利用するためには、モジュールとCSSを別に読み込みます。
import tippy from 'tippy.js';
import 'tippy.js/dist/tippy.css';
tippy関数(コンストラクタ)の利用はCDNを利用するときとおなじような感じです。
今回はReactと一緒に使ってみます。
import React from 'react';
import ReactDOM from 'react-dom/client';
import Tippy from '@tippyjs/react';
import 'tippy.js/dist/tippy.css';
import 'tippy.js/themes/light.css';
import 'tippy.js/themes/material.css';
import 'tippy.js/themes/translucent.css';
const THEMES = ["default", "light", "translucent", "material"];
function TippyApp() {
const [themeIdx, setThemeIdx] = React.useState(0);
const theme = THEMES[themeIdx % THEMES.length];
return (
<div style={{
display: 'flex',
flexDirection: 'column',
gap: '10px',
padding: '20px',
fontFamily: 'Arial, sans-serif'
}}>
<div>
<p>かんたんに文字列を表示</p>
<Tippy content="Hello" theme={theme}>
<button onClick={() => setThemeIdx(themeIdx + 1)}>Change Theme ({theme})</button>
</Tippy>
</div>
<div>
<p>JSX記法でHTML構造を作成する場合</p>
<Tippy content={(
<div>
<p>Tooltip content</p>
<p>More content here</p>
</div>
)} theme={theme}>
<button onClick={() => setThemeIdx(themeIdx + 1)}>Change Theme ({theme})</button>
</Tippy>
</div>
</div>
)
}
const rootElement = document.getElementById('root');
const root = ReactDOM.createRoot(rootElement);
root.render(
<React.StrictMode>
<TippyApp />
</React.StrictMode>
)
Reactに乗せる場合は、@tippyjs/reactも一緒に導入しなければいけませんでした。
tippy関数をuseEffectで利用しようと思ったら、状態が変わるたびにツールチップが作成されてしまいました😅
kintoneカスタマイズでの利用
TypeScriptでいつものようにkintoneのカスタマイズをします。
今回は一覧画面のボタンに分かりやすいTipsを表示しています。
import tippy from "tippy.js";
import { KintoneRestAPIClient } from "@kintone/rest-api-client"
import "tippy.js/dist/tippy.css";
import 'tippy.js/themes/light.css';
import 'tippy.js/themes/material.css';
import 'tippy.js/themes/translucent.css';
import "./sample.css";
declare const kintone: any;
const client = new KintoneRestAPIClient();
kintone.events.on(["app.record.index.show"], async (event) => {
const $$a = document.querySelector("a.recordlist-show-gaia")!;
const $$edit = document.querySelector("button.recordlist-edit-gaia")!;
const $$remove = document.querySelector("button.recordlist-remove-gaia")!;
tippy($$a, {
content: `
<p>ドキュメントレコードの詳細を表示します。</p>
`,
allowHTML: true,
});
tippy($$edit, {
content: `
<p>ドキュメントレコードを編集します。</p>
`,
allowHTML: true,
});
tippy($$remove, {
content: `
<p>ドキュメントレコードを削除します。</p>
`,
theme: 'tomato',
allowHTML: true,
});
return event;
});

こんな感じで、でっかく何が起こるかを表示します。削除ボタンはトマト色にしました。
つづきです。詳細画面でフィールドにタッチすると、フィールドの定義が見えるようにしてみました。
kintone.events.on(["app.record.detail.show"], async (event) => {
//文字列一行フィールドにツールチップを出す。
const $$p = document.createElement('p');
$$p.innerHTML = 'これはテキストフィールドのツールチップ例です。<br/>文字列一行フィールドにだけ、ツールチップを出すことができます。';
const $$menu = kintone.app.record.getHeaderMenuSpaceElement();
$$menu.appendChild($$p);
const form = await client.app.getFormFields({
app: kintone.app.getId()
});
const fields = Object.values(form.properties).filter(field => field.type === 'SINGLE_LINE_TEXT');
for (const field of fields) {
const elem = kintone.app.record.getFieldElement(field.code);
if (null == elem) continue;
tippy(elem, {
content: `
<p>
フィールドコード: ${field.code}<br/>フィールド名: ${field.label}
</p>
<pre>${JSON.stringify(field, null, 2)}</pre>
`,
allowHTML: true,
});
}
return event;
});
👆のような動きをします。
.tippy-box[data-theme~='tomato'] {
background-color: tomato;
color: greenyellow;
}
カラーテーマの作成はとっても簡単で、上記のようなCSSを作成して、呼び出します。
tippy($$remove, {
content: `
<p>ドキュメントレコードを削除します。</p>
`,
theme: 'tomato',
allowHTML: true,
});
👆呼び出しているところ
まとめ
今回は気になるライブラリとして【Tippy.js】を試してみました。
簡単にツールチップが出ちゃうので、とても楽しかったです!
ハマりポイントかなと思う点は以下です。
- HTMLで記述する場合は、allowHTML=trueを設定する
- cssはデフォルトテーマ別に読み込んであげる必要がある(自分で定義するときはまとめてよい)
- Reactでは@tippy.js/reactを利用する
- いまのところ、reactのバージョンは19だとエラーになる
今回のソースコードは以下のリポジトリで公開しています。
kintoneのプラグインを作れたら楽しそうです。
この記事は以上です。ありがとうございました。
kintoneのプラグイン開発や研修などを行っています。
お仕事のお話はこちらまで。