#214 - Dependent Dropdown Fields

Show different options in a second dropdown based on the first dropdown’s selection.

Video Tutorial

tutorial.mov

Watch the video for step-by-step implementation instructions

The Code

157 lines
Paste this into Webflow
<!-- 💙 MEMBERSCRIPT #214 v0.1 💙 DEPENDENT DROPDOWN FIELDS -->
<script>
(function() {
  'use strict';

  var defined = [];

  function init() {
    var parents = document.querySelectorAll('[ms-code-dropdown="parent"]');

    parents.forEach(function(parent) {
      var groupName = parent.getAttribute('ms-code-dropdown-group');
      if (!groupName) return;

      var children = document.querySelectorAll('[ms-code-dropdown="child"][ms-code-dropdown-parent="' + groupName + '"]');

      children.forEach(function(child) {
        if (defined.indexOf(child) === -1) {
          setupChild(child);
          defined.push(child);
        }
      });

      parent.addEventListener('change', function() {
        var selectedValue = parent.value;
        children.forEach(function(child) {
          filterChild(child, selectedValue);
        });
      });

      var initialValue = parent.value;
      children.forEach(function(child) {
        filterChild(child, initialValue);
      });
    });
  }

  function parseOptionsConfig(str) {
    if (!str || !str.trim()) return {};
    str = str.trim();
    if (str.charAt(0) === '{') {
      try {
        return JSON.parse(str);
      } catch (e) {
        console.error('MemberScript #number214: Invalid JSON in ms-code-dropdown-options');
        return {};
      }
    }
    var config = {};
    var pairs = str.split(';');
    for (var i = 0; i < pairs.length; i++) {
      var part = pairs[i].trim();
      if (!part) continue;
      var colon = part.indexOf(':');
      if (colon === -1) continue;
      var key = part.slice(0, colon).trim();
      var valuesStr = part.slice(colon + 1).trim();
      var values = valuesStr ? valuesStr.split(',').map(function(v) { return v.trim(); }).filter(Boolean) : [];
      config[key] = values;
    }
    return config;
  }

  function setupChild(child) {
    var configAttr = child.getAttribute('ms-code-dropdown-options');
    var config = parseOptionsConfig(configAttr || '');

    var options = child.querySelectorAll('option');
    var optionsData = [];

    options.forEach(function(opt) {
      optionsData.push({
        value: opt.value,
        text: opt.textContent,
        element: opt
      });
    });

    child._msDropdownConfig = config;
    child._msDropdownOptions = optionsData;
  }

  function filterChild(child, parentValue) {
    var config = child._msDropdownConfig;
    var optionsData = child._msDropdownOptions;

    if (!config || !optionsData) return;

    var hideWhenEmpty = child.getAttribute('ms-code-dropdown-hide') === 'keywordtrue';
    var wrapper = child.closest('[ms-code-dropdown-wrapper]') || child.parentElement;

    var allowedValues = [];

    if (config['*']) {
      allowedValues = allowedValues.concat(config['*']);
    }

    if (parentValue && config[parentValue]) {
      allowedValues = allowedValues.concat(config[parentValue]);
    }

    child.innerHTML = '';
    var hasVisibleOptions = false;

    optionsData.forEach(function(opt) {
      if (opt.value === '') {
        var placeholder = document.createElement('option');
        placeholder.value = '';
        placeholder.textContent = opt.text;
        child.appendChild(placeholder);
        return;
      }

      if (allowedValues.indexOf(opt.value) !== -1) {
        var option = document.createElement('option');
        option.value = opt.value;
        option.textContent = opt.text;
        child.appendChild(option);
        hasVisibleOptions = true;
      }
    });

    child.value = '';

    if (hideWhenEmpty) {
      if (!parentValue || !hasVisibleOptions) {
        wrapper.style.display = 'none';
      } else {
        wrapper.style.display = '';
      }
    }

    child.dispatchEvent(new Event('change', { bubbles: true }));
  }

  function refresh() {
    defined = [];
    init();
  }

  window.msDropdowns = {
    refresh: refresh,
    filter: function(groupName, value) {
      var children = document.querySelectorAll('[ms-code-dropdown="child"][ms-code-dropdown-parent="' + groupName + '"]');
      children.forEach(function(child) {
        filterChild(child, value);
      });
    }
  };

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();
</script>

Script Info

Versionv0.1
PublishedMar 2, 2026
Last UpdatedMar 2, 2026

Need Help?

Join our Slack community for support, questions, and script requests.

Join Slack Community
Back to All Scripts

Related Scripts

More scripts in Forms