Using option groups (<OPTGROUP>) in Forms 2.0 picklists

Though Marketo forms use standard HTML input types (which is a very good thing for cross-platform compatibility) there are a few subtypes and niche uses that aren't supported unless you use a little JS to enhance the form.

One of the classic HTML form features is the <OPTGROUP> tag, which allows you to group together <SELECT> (i.e. picklist) <OPTION>s under a relevant label.

The label itself can't be selected, but helps a lot with information clarity. OPTGROUPs can help you make shorter forms and avoid complex visibility rules:

ss

Marketo's form editor doesn't natively support OPTGROUPs, but they're extremely easy to enable with a little code. Include this JS in your page:

MktoForms2.whenRendered(function(form) {
  var formEl = form.getFormElem()[0],
      arrayify = getSelection.call.bind([].slice);

  arrayify(formEl.querySelectorAll('SELECT'))
    .forEach(function(selectEl) {
      var currentOg;
      arrayify(selectEl.querySelectorAll('OPTION'))
        .forEach(function(o, idx) {
          if (o.value == '[OPTGROUP]') {
            currentOg = document.createElement('OPTGROUP');
            currentOg.label = o.textContent;
            selectEl.appendChild(currentOg);
            selectEl.removeChild(o);
          } else {
            if (currentOg) currentOg.appendChild(o);
          }
      });
    });
});

Now, in the Form Editor, add your OPTGROUPs in-between your OPTIONs, setting the name to the group name and the value to the magic string "[OPTGROUP]" (with the square brackets, without the quotes):

ss

The JS takes care of turning each [OPTGROUP] into a real <OPTGROUP> enclosing the following set of options.

Note groups work in multi-select widgets, too, for cases where the values aren't mutually exclusive:

ss

Why you need whenRendered() here

Detail-oriented readers might wonder why I called MktoForms2.whenRendered here instead of the more common whenReady. The reason is that when you use Visibility Rules, <SELECT> elements may be created or destroyed as people change field values. So you need to catch each time the form re-renders in order to make sure to create all desired <OPTGROUP>s.

There actually are a lot of potentially broken Forms 2.0 snippets, including my own, that should be using whenRendered to avoid surprises if users add VRs.