セレクトボックス — Tom Select

フォーム入力 初級

このコンポーネントについて

複数の値をまとめて選択する「マルチセレクト」を、軽量ライブラリ Tom Select で実装する例です。 標準の <select multiple> は選択肢が多いと目的の項目を探しにくく、Ctrl/Shiftクリックという操作もユーザーに伝わりにくいという課題があります(自作での複数選択パターンは セレクトボックス(複数選択) を参照)。 Tom Select を使うと、インクリメンタル検索・選択済み項目のタグ表示・最大選択数の制限を、わずかな初期化コードで実装できます。 このページでは、問い合わせの対応カテゴリを複数選択する業務フォームを題材に、Tom Select の基本的な組み込み方を確認・コピペできます。

  • インクリメンタル検索 — 入力するたびに選択肢を絞り込み、20件近い候補からでも素早く探せる
  • 選択済みタグ表示 — 選んだ項目はタグ形式でインライン表示され、× ボタンでその場から削除できる
  • 最大選択数の制限maxItems オプションで選択できる件数の上限を設け、上限到達時は残りの候補を選べなくする
  • 軽量・jQuery非依存 — CDN読み込みだけで導入でき、他ライブラリへの依存がない

実装のポイント・注意点

Tom Select の初期化は new TomSelect(セレクタ, オプション) の1行で完結します。今回は選択済みタグに × ボタンを表示するため remove_button プラグインを指定しています。このプラグインを付けないと、タグ本体をクリックして選択解除する挙動になり、「タグ表示」の使い勝手が伝わりにくくなります。

maxItems オプションで選択できる件数の上限を設定すると、上限に達した時点で残りの候補が自動的に選択不可(グレーアウト)になります。業務フォームでは「対応カテゴリは最大5件まで」のようにルールを決めたい場面が多く、実装側で追加の制御コードを書く必要がありません。

選択中の値を取得するには instance.getValue() を使います。multiple 属性を付けた場合は配列で返り、単一選択モードとは戻り値の型が変わる点に注意してください。全選択解除は instance.clear() で行えます。

HTML・CSS・JavaScriptで実装しており、Tom Selectライブラリ(CDN)を1本追加するだけで動きます。フレームワーク不要でコピペすぐに使えます。

デモ

サンプルソース

3つのファイルを同じフォルダに保存し、index.html をブラウザで開くとすぐに動作確認できます。
ファイル名:index.html / style.css / script.js — 保存時の文字コードは UTF-8 を指定してください(Shift-JISだと日本語が文字化けします)。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>マルチセレクト(Tom Select)サンプル</title>
  <link rel="stylesheet" href="./style.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tom-select/2.6.1/css/tom-select.min.css">
</head>
<body>

<div class="fs5-wrapper">
  <label class="fs5-label" for="fs5-select">対応カテゴリ(複数選択可・最大5件)</label>
  <select id="fs5-select" class="fs5-select" multiple placeholder="カテゴリを検索・選択">
    <option value="shipping">配送・出荷</option>
    <option value="return">返品・交換</option>
    <option value="billing">請求・支払い</option>
    <option value="quote">見積もり</option>
    <option value="contract">契約</option>
    <option value="account">アカウント登録</option>
    <option value="login">ログイントラブル</option>
    <option value="password">パスワード再設定</option>
    <option value="plan">プラン変更</option>
    <option value="cancel">解約</option>
    <option value="campaign">キャンペーン</option>
    <option value="coupon">クーポン</option>
    <option value="outage">システム障害</option>
    <option value="feature">機能要望</option>
    <option value="howto">操作方法</option>
    <option value="security">セキュリティ</option>
    <option value="api">API連携</option>
    <option value="other">その他</option>
  </select>
  <button class="fs5-submit-btn" id="fs5-submit">決定</button>
  <div class="fs5-result" id="fs5-result" aria-live="polite"></div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/tom-select/2.6.1/js/tom-select.complete.min.js"></script>
<script src="./script.js"></script>
</body>
</html>
/* === マルチセレクト(Tom Select)サンプル ===
   :root の変数を書き換えると色を一括変更できます */
:root {
  --color-accent: #2B7FE8;
  --color-text:   #1A2332;
  --color-border: #D0D7E0;
  --color-muted:  #9AA5B4;
  --color-bg:     #F4F6F9;
  --color-danger: #E65100;
}
* { box-sizing: border-box; }
body { font-family: sans-serif; color: var(--color-text); padding: 24px; max-width: 480px; }

.fs5-wrapper { display: flex; flex-direction: column; }
.fs5-label {
  display: block;
  margin-bottom: 8px;
  font-weight: 600;
}

/* Tom Select はセレクトを .ts-wrapper に置き換えるため、外観はここで上書きする */
.ts-wrapper.multi .ts-control {
  border: 1.5px solid var(--color-border);
  border-radius: 8px;
  padding: 6px 8px;
}
.ts-wrapper.multi.focus .ts-control {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px rgba(43, 127, 232, 0.12);
}
.ts-control .item {
  background: var(--color-accent);
  color: #fff;
  border-radius: 4px;
  padding: 3px 6px;
}
.ts-dropdown .active {
  background: #EAF2FF;
}

/* 決定ボタン */
.fs5-submit-btn {
  margin-top: 16px;
  align-self: flex-start;
  padding: 8px 20px;
  font-size: 14px;
  font-weight: 700;
  color: #fff;
  background: var(--color-accent);
  border: none;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s;
}
.fs5-submit-btn:hover { background: #1a6fd1; }

/* 結果エリア */
.fs5-result { margin-top: 14px; }
.fs5-result.has-value {
  padding: 12px 16px;
  border: 1.5px solid var(--color-border);
  border-radius: 8px;
  background: #fff;
  font-size: 14px;
}
.fs5-result.has-value ul { margin: 0; padding-left: 18px; }
.fs5-result.has-error { font-size: 13px; color: var(--color-danger); padding: 4px 0; }

/* リセットボタン */
.demo-controls { margin-top: 12px; }
.reset-btn {
  padding: 6px 16px;
  font-size: 13px;
  color: #5A6A7A;
  background: #fff;
  border: 1.5px solid var(--color-border);
  border-radius: 6px;
  cursor: pointer;
}
.reset-btn:hover { background: var(--color-bg); border-color: var(--color-muted); }
// カテゴリ名(テキスト)をvalueから引くための対応表
var categoryLabels = {
  shipping: "配送・出荷", return: "返品・交換", billing: "請求・支払い",
  quote: "見積もり", contract: "契約", account: "アカウント登録",
  login: "ログイントラブル", password: "パスワード再設定", plan: "プラン変更",
  cancel: "解約", campaign: "キャンペーン", coupon: "クーポン",
  outage: "システム障害", feature: "機能要望", howto: "操作方法",
  security: "セキュリティ", api: "API連携", other: "その他"
};

// Tom Select を初期化する
// remove_button プラグインでタグに×ボタンを表示し、maxItemsで最大5件に制限する
var tomSelectInstance = new TomSelect('#fs5-select', {
  plugins: ['remove_button'],
  maxItems: 5,
  placeholder: 'カテゴリを検索・選択'
});

// 決定ボタン:選択中の値を結果エリアに一覧表示する
document.getElementById('fs5-submit').addEventListener('click', function () {
  var values = tomSelectInstance.getValue(); // multiple指定時は配列で返る
  var resultEl = document.getElementById('fs5-result');

  if (values.length === 0) {
    resultEl.className = 'fs5-result has-error';
    resultEl.textContent = '1つ以上選択してください';
    return;
  }

  // 選択されたvalueに対応するテキストでリストを作る(innerHTMLに変数を結合しない)
  var list = document.createElement('ul');
  values.forEach(function (value) {
    var li = document.createElement('li');
    li.textContent = categoryLabels[value];
    list.appendChild(li);
  });
  resultEl.className = 'fs5-result has-value';
  resultEl.textContent = '';
  resultEl.appendChild(list);
});

// リセット:全選択を解除し、結果エリアをクリアする
function resetDemo() {
  tomSelectInstance.clear();
  var resultEl = document.getElementById('fs5-result');
  resultEl.className = 'fs5-result';
  resultEl.textContent = '';
}

AI用プロンプト

以下のプロンプトをコピーしてAIに渡すと、同様のコンポーネントを生成できます。

ChatGPTやClaudeにこのプロンプトを渡すと、同様のコンポーネントをゼロから生成・カスタマイズできます。選択肢の内容や最大選択数など、要件を追記して使うのがおすすめです。

※ このプロンプトを使ってもデモとまったく同じ動作にならない場合があります。AIの解釈や生成タイミングによって差が出ることをご了承ください。

💡 jQuery・Vue・React など特定のライブラリで実装したい場合は、プロンプトの末尾に「〇〇を使って実装してください」と追記してください。

# マルチセレクト(Tom Select)作成依頼

## 概要
Tom Select(軽量マルチセレクトライブラリ)を使って、検索・タグ表示・最大選択数の制限に対応した複数選択フォームUIを作成してください。

## 要件
- 標準の `<select multiple>` 要素を Tom Select で初期化する
- 入力するとリアルタイムに候補が絞り込まれる(インクリメンタル検索)
- 選択した項目はタグ形式で表示され、`×` ボタンでその場から削除できる(`remove_button` プラグインを使用)
- 最大選択数を5件に制限し、上限到達後は残りの候補を選択できないようにする(`maxItems` オプション)
- 「決定」ボタン押下で選択中の全項目名を結果エリアに一覧表示する。0件のまま押下した場合は警告を表示する
- リセットボタンで全選択を解除し初期状態に戻す

## 技術仕様
- HTML / CSS / バニラJavaScript で実装
- 外部ライブラリ:Tom Select(CDN: `https://cdnjs.cloudflare.com/ajax/libs/tom-select/2.6.1/css/tom-select.min.css` と `https://cdnjs.cloudflare.com/ajax/libs/tom-select/2.6.1/js/tom-select.complete.min.js`)
- レスポンシブ対応:必要

## 動作詳細
選択肢(18件): 配送・出荷, 返品・交換, 請求・支払い, 見積もり, 契約, アカウント登録, ログイントラブル, パスワード再設定, プラン変更, 解約, キャンペーン, クーポン, システム障害, 機能要望, 操作方法, セキュリティ, API連携, その他
Tom Select のインスタンスは `new TomSelect(selector, options)` で生成する。
選択中の値は `instance.getValue()` で配列として取得できる(複数選択時)。
リセットは `instance.clear()` で全選択解除できる。

## 出力形式
HTML・CSS・JavaScriptを分けて出力してください。
各ファイルは単独でコピー&ペーストして使えるよう記述してください。