Destyling a Marketo form (for easier CSS restyling)

It's easier to customize a Marketo form if it's completely destyled to start. A float or margin-left that doesn't seem to respond to !important can drive a designer crazy, and time spent on CSS specificity & cascade behavior isn't well spent.

My li'l snippet for removing Marketo's built-in styles has seen a lot of use via the Community and a few code versions (now at the venerable v1.104) but it hasn't appeared on the blog before.

Here's a sample form with the Simple theme:

ss

And here's that same form after running destyleMktoForm to reset it to browser defaults (check out the Times New Roman):

Yes, it's supposed to be ugly! All of Marketo's layout, visibility, and font CSS has been removed, and the world is your oyster from here. I'm not here to show you how to make it pretty (I get paid for that, sometimes!) but now you can assure your designer that they won't have to do any CSS overrides. They can look at the <form>'s HTML markup and style away.

About the code

Let's dive into the destyleMktoForm function a bit, since I always insist on a teachable moment. The goals:

  • hide the form to start: see visibility: hidden in the CodePen CSS pane[1]
  • remove all style= attributes within the form (these are really pesky to override)
  • disable local <style> sheets within the form
  • disable remote <link rel="stylesheet"> includes within the document <head>, if they were injected by the Forms 2.0 library
  • show the form with visibility: visible
  • re-run the destyling code whenever the form is re-rendered, i.e. via Visibility Rules, by calling the function from MktoForms2.whenRendered instead of whenReady (thanks, Mark!)

So we end up needing two simple loops, one for the style attrs and one for the <link> & <style> els.

Remove style attributes

var styledEls = arrayFrom(formEl.querySelectorAll("[style]")).concat(formEl);
	
styledEls.forEach(function(el) {
  el.removeAttribute("style");
});

Here I'm selecting all the child elements of the <form> element that have a style attribute (regardless of the value and regardless of the type of element — who cares, we just want to destyle it!).

Then I add to the array the <form> element itself (which also has a style).

Then loop over the array and remove the attribute. Completely easy.

(arrayFrom is just a naïve function to convert array-like NodeLists, as returned by querySelectorAll, to true Arrays so you can run all the fun JS Array methods. Don't worry about it, just use it.)

Disable <link> and <style> stylesheets

var styleSheets = arrayFrom(document.styleSheets);
	
styleSheets.forEach(function(ss) {
  if ( [mktoForms2BaseStyle,mktoForms2ThemeStyle].indexOf(ss.ownerNode) != -1 ||
       formEl.contains(ss.ownerNode) ) {
      ss.disabled = true;
    }
});

Get an array of stylesheets. forEach over the array and if either of the following is true…

  1. the stylesheet has one of Marketo's known stylesheet IDs (base style and, in this case, Simple theme style)[2]
  2. the stylesheet is a child of the Marketo <form> element

… then set the stylesheet's disabled attribute (a very cool, age-old feature) to true.

One other thing

One thing you may want to do (and which I do in my demo) is un-de-style the .mktoAsterix element:

.mktoForm .mktoAsterix {
	display: none;
}
.mktoForm .mktoRequiredField .mktoAsterix {
	display: block;
}

See, Marketo includes the <div class="mktoAsterix">*</div> (denoting required fields) in the form markup even for fields that aren't required. Then display: none hides fields that aren't required. So when you clear all the styles, you see a lot of asterisks to clean up.

Of course you're free to work with all the rules off. This is just a suggestion.


Notes

[1] Why not display: none here? Because the forms library depends on the form being in the flow to determine its dimensions. Test and you'll see the diff.

[2] Not mentioning one HTML factoid I'm taking advantage of here for shorter code. Anyone notice it?