動的ドロップダウンリスト 実装解説|Dynamic Dropdown List JS Guide

動的ドロップダウンリスト デザイン見本

選択に応じて次のプルダウンの中身が変わる「連動プルダウン」の実装解説。コピーしてすぐに使えるHTML・CSS・JSのコードを掲載。

① 2つの連動 — 1つ目の選択で2つ目の候補が変わる

HTML
<div class="input-block">
  <div class="pick-block">
    <label>大分類:
      <select id="cat-pick-1">
        <option>選択してください</option>
      </select>
    </label>
  </div>
  <div class="pick-block">
    <label>小分類:
      <select id="sub-pick-1">
        <option>選択してください</option>
      </select>
    </label>
  </div>
</div>
CSS
.input-block {
  display: flex;
  flex-direction: column;
}
.pick-block {
  margin-bottom: 16px;
}
select, label {
  height: 32px;
  font-size: 14px;
}
JS
var categories = [
  'エコグッズ',
  '衛生グッズ',
  '防災グッズ'
];

var subCategories = [
  {category: 'エコグッズ', name: '天然素材'},
  {category: 'エコグッズ', name: 'リサイクル素材'},
  {category: '衛生グッズ', name: 'マスク'},
  {category: '衛生グッズ', name: '除菌'},
  {category: '防災グッズ', name: 'セット物'},
  {category: '防災グッズ', name: 'ライト'}
];

var catPick1 = document.getElementById('cat-pick-1');
var subPick1 = document.getElementById('sub-pick-1');

categories.forEach(function(cat) {
  var opt = document.createElement('option');
  opt.textContent = cat;
  catPick1.appendChild(opt);
});

catPick1.addEventListener('input', function() {
  var opts = subPick1.querySelectorAll('option');
  opts.forEach(function(o) { o.remove(); });

  var first = document.createElement('option');
  first.textContent = '選択してください';
  subPick1.appendChild(first);

  subCategories.forEach(function(sub) {
    if (catPick1.value === sub.category) {
      var opt = document.createElement('option');
      opt.textContent = sub.name;
      subPick1.appendChild(opt);
    }
  });
});
addEventListener(‘input’) + forEach

大分類の change / input イベントを検知し、小分類のプルダウンを毎回リセットしてから該当する項目だけを再生成します。小分類のデータにはオブジェクト配列を使い、category プロパティで大分類と紐付けることで、if 文1つでフィルタリングできます。

② 2つの連動 + 選択不可 — 未選択時はクリック無効

HTML
<div class="input-block">
  <div class="pick-block">
    <label>大分類:
      <select id="cat-pick-2">
        <option>選択してください</option>
      </select>
    </label>
  </div>
  <div class="pick-block">
    <label>小分類:
      <select id="sub-pick-2" disabled>
        <option>選択してください</option>
      </select>
    </label>
  </div>
</div>
CSS
.input-block {
  display: flex;
  flex-direction: column;
}
.pick-block {
  margin-bottom: 16px;
}
select, label {
  height: 32px;
  font-size: 14px;
}
JS
var categories = [
  'エコグッズ',
  '衛生グッズ',
  '防災グッズ'
];

var subCategories = [
  {category: 'エコグッズ', name: '天然素材'},
  {category: 'エコグッズ', name: 'リサイクル素材'},
  {category: '衛生グッズ', name: 'マスク'},
  {category: '衛生グッズ', name: '除菌'},
  {category: '防災グッズ', name: 'セット物'},
  {category: '防災グッズ', name: 'ライト'}
];

var catPick2 = document.getElementById('cat-pick-2');
var subPick2 = document.getElementById('sub-pick-2');

categories.forEach(function(cat) {
  var opt = document.createElement('option');
  opt.textContent = cat;
  catPick2.appendChild(opt);
});

catPick2.addEventListener('input', function() {
  var opts = subPick2.querySelectorAll('option');
  opts.forEach(function(o) { o.remove(); });

  var first = document.createElement('option');
  first.textContent = '選択してください';
  subPick2.appendChild(first);

  subPick2.disabled = false;

  if (catPick2.value === '選択してください') {
    subPick2.disabled = true;
    return;
  }

  subCategories.forEach(function(sub) {
    if (catPick2.value === sub.category) {
      var opt = document.createElement('option');
      opt.textContent = sub.name;
      subPick2.appendChild(opt);
    }
  });
});
disabled 属性による操作制御

HTMLの disabled 属性を付けておくと、ユーザーはそのプルダウンをクリックできなくなります。大分類が選択された時点で disabled = false にして操作を許可し、「選択してください」に戻った場合は再度 disabled = true で無効化します。こうすることで、まだ選べない項目を確実にロックできます。

③ 3つの連動 — 大分類 → 小分類 → 商品名

HTML
<div class="input-block">
  <div class="pick-block">
    <label>大分類:
      <select id="cat-pick-3">
        <option>選択してください</option>
      </select>
    </label>
  </div>
  <div class="pick-block">
    <label>小分類:
      <select id="sub-pick-3" disabled>
        <option>選択してください</option>
      </select>
    </label>
  </div>
  <div class="pick-block">
    <label>商品名:
      <select id="prod-pick" disabled>
        <option>選択してください</option>
      </select>
    </label>
  </div>
</div>
CSS
.input-block {
  display: flex;
  flex-direction: column;
}
.pick-block {
  margin-bottom: 16px;
}
select, label {
  height: 32px;
  font-size: 14px;
}
JS
var categories = [
  'エコグッズ',
  '衛生グッズ',
  '防災グッズ'
];

var subCategories = [
  {category: 'エコグッズ', name: '天然素材'},
  {category: 'エコグッズ', name: 'リサイクル素材'},
  {category: '衛生グッズ', name: 'マスク'},
  {category: '衛生グッズ', name: '除菌'},
  {category: '防災グッズ', name: 'セット物'},
  {category: '防災グッズ', name: 'ライト'}
];

var products = [
  {subCategory: '天然素材', name: 'バンブーマグカップ'},
  {subCategory: '天然素材', name: 'リユースコーヒータンブラー'},
  {subCategory: 'リサイクル素材', name: 'リサイクルコットンバッグ'},
  {subCategory: 'リサイクル素材', name: '再生PETブランケット'},
  {subCategory: 'マスク', name: '不織布マスク'},
  {subCategory: 'マスク', name: 'ウレタンマスク'},
  {subCategory: '除菌', name: '除菌スプレー'},
  {subCategory: '除菌', name: '除菌ウェットティッシュ'},
  {subCategory: 'セット物', name: '防災10点セット'},
  {subCategory: 'セット物', name: '防災20点セット'},
  {subCategory: 'ライト', name: 'LED電灯'},
  {subCategory: 'ライト', name: 'ランタン'}
];

function firstOpt() {
  var f = document.createElement('option');
  f.textContent = '選択してください';
  return f;
}

function optClear(node) {
  var opts = document.querySelectorAll(node);
  opts.forEach(function(o) { o.remove(); });
}

var catPick3 = document.getElementById('cat-pick-3');
var subPick3 = document.getElementById('sub-pick-3');
var prodPick = document.getElementById('prod-pick');

categories.forEach(function(cat) {
  var opt = document.createElement('option');
  opt.textContent = cat;
  catPick3.appendChild(opt);
});

catPick3.addEventListener('input', function() {
  optClear('#sub-pick-3 > option');
  subPick3.appendChild(firstOpt());
  subPick3.disabled = false;

  optClear('#prod-pick > option');
  prodPick.appendChild(firstOpt());
  prodPick.disabled = true;

  if (catPick3.value === '選択してください') {
    subPick3.disabled = true;
    return;
  }

  subCategories.forEach(function(sub) {
    if (catPick3.value === sub.category) {
      var opt = document.createElement('option');
      opt.textContent = sub.name;
      subPick3.appendChild(opt);
    }
  });
});

subPick3.addEventListener('input', function() {
  optClear('#prod-pick > option');
  prodPick.appendChild(firstOpt());
  prodPick.disabled = false;

  if (subPick3.value === '選択してください') {
    prodPick.disabled = true;
    return;
  }

  products.forEach(function(prod) {
    if (subPick3.value === prod.subCategory) {
      var opt = document.createElement('option');
      opt.textContent = prod.name;
      prodPick.appendChild(opt);
    }
  });
});
関数による共通処理のまとめ

firstOpt() で「選択してください」の option を生成し、optClear() で既存の option を全消去する共通関数を用意します。3段連動では、大分類を変更した時に小分類だけでなく商品名のプルダウンもリセットし disabled にすることで、古い選択肢が残るのを防ぎます。この「上位が変わったら下位をすべてリセット」が多段連動の定石です。

注意点:WAF環境(WordPress等)にそのまま貼り付ける場合、変数名に select や id を含めるとブロックされることがあります。コピペ用コードでは select の代わりに pick、id の代わりに key など別の単語を使っています。

当サイトで公開しているWebデザインやUIの実装例は、一覧として以下記事に纏めています。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次