はじめに
新しいWebアプリを開いた瞬間、「で、まず何をすればいいの?」と固まってしまった経験はありませんか。開発者にとっては自明な画面でも、初めて訪れたユーザーには機能の場所も操作の順番も分かりません。せっかく作り込んだ機能が「気づかれないまま」離脱される——これはプロダクト開発で最ももったいない瞬間です。
この課題を解決する定番の手法が、画面上の要素を順番にハイライトしながら説明していく「プロダクトツアー」です。そして、それをわずか数行のコードで実現できるのが、今回紹介するIntro.jsです。10年以上メンテナンスが続く老舗ライブラリで、GitHubでは23,000を超えるスターを集めています。
とはいえ、説明を読むより先に実際にツアーが動く様子を見た方が早いと思います。先に挙動を見たい方はこちらからどうぞ。
Intro.jsとは
Intro.jsは、Webサイトやアプリケーションにステップバイステップのガイドツアーやヒント表示を組み込むための、軽量なユーザーオンボーディングライブラリです。依存ライブラリなしの素のJavaScriptで書かれており、フレームワークを問わず利用できます。2025年にはv8系がリリースされ、TypeScriptベースの新しいAPIに刷新されました。
主な特徴
- 導入が簡単 - HTML要素に
data-intro属性を付けるだけでもツアーが作れます。既存のマークアップをほとんど変更せずに導入できます - 依存ゼロで軽量 - jQueryなどの外部依存がなく、CSSとJSを読み込むだけで動作します
- ツアーとヒントの2つのモード - 順番に案内する「ツアー」と、要素の横にパルスアイコンを常駐させる「ヒント」を使い分けられます
- カスタマイズ性が高い - ボタンのラベル、進捗バー、テーマ、コールバックなど細かく制御できます
なお、ライセンスはAGPLv3と商用ライセンスのデュアルライセンスです。オープンソースプロジェクトでは無料で使えますが、商用プロダクトに組み込む場合は商用ライセンスの購入が必要になる点だけ注意してください。
インストール
npmまたはyarnでインストールできます。
# npm
npm install intro.js --save
# yarn
yarn add intro.js
ビルドツールを使わない場合は、CDNから直接読み込むこともできます。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/intro.js/minified/introjs.min.css">
<script src="https://cdn.jsdelivr.net/npm/intro.js/minified/intro.min.js"></script>
npmで導入した場合は、次のようにインポートします。
import introJs from "intro.js";
import "intro.js/introjs.css";
Intro.jsのサンプルを動かす
Intro.jsの基本は、案内したい要素にdata-intro(説明文)とdata-step(表示順)の属性を付けておき、introJs.tour().start()を1回呼ぶだけです。下のサンプルは「ダッシュボード」を模した3つの要素にこの属性を仕込んであり、ボタンを押すといつでも同じツアーを開始できます。ツアー中はonChangeコールバックが呼ばれるので、今どの要素を案内しているかをコンソールでも確認できます。
要点だけを抜き出すと、次のようになります。
<header data-intro="ここがヘッダーです" data-step="1">Dashboard</header>
<nav data-intro="メニューはこちら" data-step="2">Home / Settings</nav>
<button data-intro="新規作成はこちらから" data-step="3">新規作成</button>
introJs.tour()
.onChange((element) => console.log('現在の要素:', element))
.start()
実際に動かせるのが下のサンプルです。「ツアーを開始」ボタンを押すと、ヘッダー→ナビゲーション→ボタンの順にオーバーレイとツールチップが移動します。
data-stepの数字を入れ替えると、案内される順番もそのまま変わります。要素を1つ増やしてdata-step="4"を振れば、ツアーはコード修正なしで4ステップに拡張されます。ツールチップの表示位置を変えたい場合は、各要素にdata-position="right"のような属性を追加すればIntro.js側で自動的に調整してくれます。
基本的な使い方
Intro.jsのツアーは2通りの方法で定義できます。まずは最も手軽な、HTML属性を使う方法から見てみましょう。
HTML属性でステップを定義する
案内したい要素にdata-intro(説明文)とdata-step(表示順)を付けます。
<header data-intro="ここがダッシュボードのヘッダーです" data-step="1">
<h1>My Dashboard</h1>
</header>
<nav data-intro="メニューはこちらから切り替えられます" data-step="2">
...
</nav>
<button data-intro="データの追加はこのボタンから行います" data-step="3">
新規作成
</button>
あとはJavaScriptで1行実行するだけです。
introJs.tour().start();
これだけで、オーバーレイ付きのハイライトとツールチップが順番に表示されるツアーが完成します。拍子抜けするほど簡単です。
JavaScriptオブジェクトでステップを定義する
マークアップを汚したくない場合や、ステップを動的に組み立てたい場合は、setOptions()にステップの配列を渡す方法が使えます。
introJs.tour().setOptions({
steps: [
{
title: "ようこそ!",
intro: "このアプリの使い方を30秒でご案内します 👋"
},
{
element: document.querySelector("#sidebar"),
title: "ナビゲーション",
intro: "各機能へはこのサイドバーから移動できます"
},
{
element: document.querySelector("#create-button"),
title: "最初の一歩",
intro: "まずはここから最初のプロジェクトを作ってみましょう!"
}
]
}).start();
elementを省略したステップは、画面中央にモーダル風に表示されます。ツアーの冒頭の挨拶や締めのメッセージに便利です。
日本語UIにカスタマイズする
デフォルトのボタンは「Next」「Back」「Done」と英語表記なので、日本語アプリでは差し替えましょう。進捗バーの表示などもオプションで制御できます。
introJs.tour().setOptions({
nextLabel: "次へ",
prevLabel: "戻る",
doneLabel: "完了",
showProgress: true, // 進捗バーを表示
showBullets: false, // ドットのページネーションを非表示
exitOnOverlayClick: false, // オーバーレイのクリックで閉じない
steps: [ /* ... */ ]
}).start();
実践的なユースケース
ここからは、実際のプロダクトで使えるパターンを紹介します。
初回訪問時だけツアーを表示する
オンボーディングツアーで最も多い要件が「初回だけ表示したい」です。localStorageと組み合わせれば簡単に実現できます。
import introJs from "intro.js";
import "intro.js/introjs.css";
const TOUR_KEY = "dashboard-tour-done";
function startOnboardingTour() {
if (localStorage.getItem(TOUR_KEY) === "true") {
return; // すでに見たユーザーには表示しない
}
introJs.tour()
.setOptions({
nextLabel: "次へ",
prevLabel: "戻る",
doneLabel: "はじめる",
showProgress: true,
steps: [
{ title: "ようこそ!", intro: "初回だけ簡単なツアーをご案内します" },
{ element: document.querySelector("#search"), intro: "検索はここから" },
{ element: document.querySelector("#settings"), intro: "設定はこちらです" }
]
})
.onComplete(() => {
localStorage.setItem(TOUR_KEY, "true");
})
.onExit(() => {
// 途中離脱でも再表示しない場合はこちらでも保存
localStorage.setItem(TOUR_KEY, "true");
})
.start();
}
startOnboardingTour();
onCompleteは最後まで見終わったとき、onExitはEscキーなどで途中終了したときに呼ばれます。なお、v8にはdontShowAgainオプションも用意されており、「次回から表示しない」チェックボックスをツアー自体に組み込むこともできます。
実際にlocalStorageとonComplete/onExitが連動する様子を、下のサンプルで確認できます。初回はツアーが自動的に始まり、完了または途中終了するとlocalStorageに記録が残るため、ページを再読み込みしても2回目以降は表示されません。「見た記録をリセット」ボタンを押すと、また初回の状態に戻せます。
onCompleteとonExitのどちらでも同じキーをlocalStorageに書き込んでいますが、たとえばonExit側だけ書き込みを外せば「最後まで見た人だけ既読扱いにする」という挙動に変えられます。
機能リリース時のアナウンスに使う
新機能をリリースしたとき、その機能だけを1ステップでハイライトするのも効果的です。
introJs.tour()
.setOptions({
doneLabel: "試してみる",
steps: [
{
element: document.querySelector("#export-button"),
title: "🎉 新機能:エクスポート",
intro: "作成したレポートをPDFで出力できるようになりました!"
}
]
})
.onComplete(() => {
document.querySelector("#export-button").focus();
})
.start();
ヒントモードで「押しつけない」ガイドを作る
ツアーは強制的に画面を占有するため、人によっては煩わしく感じます。そこで使えるのがヒント(Hints)モードです。要素の横に小さなパルスアイコンを表示し、ユーザーがクリックしたときだけ説明を出します。
<button data-hint="ここからテーマを切り替えられます" data-hint-position="bottom-right">
🌙
</button>
introJs.hint().addHints();
下のサンプルでは、ボタンの右下にdata-hint属性で仕込んだパルスアイコンが表示されます。Intro.jsのintroJs.hint().addHints()を呼ぶだけで、要素を探してアイコンを自動配置してくれるので、ツアーのようにステップを配列で管理する必要がありません。アイコンをクリックすると、data-hintの説明文がツールチップで表示されます。
data-hint-positionをtop-leftなどに変えるとアイコンの位置が変わり、data-hintの文言を書き換えるだけでツールチップの説明も差し替えられます。要素を増やしてdata-hintを追加すれば、addHints()を呼び直さなくても新しいヒントが自動的に対象に加わります。
「知りたい人だけが知れる」控えめなガイドなので、ツアーと組み合わせて「初回はツアー、以降はヒント」という設計にすると、しつこさのないオンボーディングが実現できます。
Reactで使う
Reactの場合は、useEffect内でツアーを起動し、対象要素はrefではなくセレクタで指定するのが手軽です。
import { useEffect } from "react";
import introJs from "intro.js";
import "intro.js/introjs.css";
export function DashboardTour() {
useEffect(() => {
const tour = introJs.tour().setOptions({
nextLabel: "次へ",
prevLabel: "戻る",
doneLabel: "完了",
steps: [
{ element: "#chart-area", intro: "売上の推移がここに表示されます" },
{ element: "#filter-panel", intro: "期間の絞り込みはこちら" }
]
});
tour.start();
return () => {
tour.exit(true); // アンマウント時にツアーを閉じる
};
}, []);
return null;
}
Reactに特化した公式ラッパーとしてintro.js-reactも公開されているので、宣言的に書きたい場合はそちらも検討してみてください。
まとめ
Intro.jsを使えば、これまで「作るのが面倒で後回しにしていた」プロダクトツアーを、数行のコードで導入できます。ポイントを振り返りましょう。
data-intro属性を付けてintroJs.tour().start()を呼ぶだけでツアーが動くsetOptions()でステップをJSONとして定義すれば、マークアップを汚さず動的な制御も可能onCompleteやonExitのコールバックとlocalStorageで「初回だけ表示」が実現できる- 押しつけがましくないヒントモードとの使い分けが効果的
- 商用利用時はライセンス(AGPLv3 / 商用デュアル)に注意
どんなに優れた機能も、ユーザーに見つけてもらえなければ存在しないのと同じです。まずは自分のアプリの「最初の3ステップ」をツアーにするところから試してみてはいかがでしょうか。
