Our Javascript Approach

Cantilever believes that simpler is better when it comes to websites. As such, we have adopted a Vanilla JS approach. Most of our sites have relatively straghtforward JS requirements. When we need to reach for React or Vue we can do that, but in most cases we find those frameworks to be overkill.

For more Vanilla JS tips, check out Chris Fernandini’s writing:

Typical Architecture

One advantage of working in Vanilla JS is that our javascript layer on any given site can morph to the specific requirements of that site.

In the majority of cases, we are working with HTTP/2 and no longer need ES5 support, so we do not compile or bundle or our Javascript. We simply link to scripts in the footer like the good old days.


Update: We are now using browser-native ES6 modules when browser support on a project permits it.

We use the defer tag to ensure that the page can load independently from the JS. Most sites, especially those with a backend, should have some kind of asset queue which produces those footer script tags rather than having them literally hard-coded into the footer. That said, we do definitely have sites where we just throw script tags in the footer, and that’s OK. Here is one very nuanced approach we used:

Commonly, we have two kinds of script on a site:

  1. Global functionality that should run on page load and is not tied 1-1 to a specific DOM element but runs broadly in the global namespace
  2. Objects which are instantiated with a 1-1 relationship to a specific DOM element or set of elements

Sometimes the distinction is tough to discern. Some tracking or lightbox systems, for instance, might not bind to a specific DOM element but provide a global API for elements with specific data attributes to trigger actions. That would generally fall into #1 but could be argued either way.

Generally, if the file contains a JS constructor function which is then instantiated for some set of DOM elements, see it as #2. Otherwise, #1 is probably better.

The file structure looks like:

  • app.js – sets a global namespace and performs any high-level utility functionality like redirecting to a browser unsupported page when needed
  • lib – a directory with all third-party scripts we need @
  • utilities – A directory with all files that cover global functionality (#1 above)
  • objects (formerly called components) – files for objects which are tied specifically to some DOM element (#2 above). These usually match a .lessfile within the source/less/05-objects/ directory.


We have several projects on Backbone. The same architecture can apply to such projects, it’s just that the objects you create in script style #2 are Backbone views/models rather than plan JS objects.

We also maintain some sites which have Vue or React code. When working within those codebases, please think deeply about the existing coding standard and try to stick to it as well as you can.

Coding Standards

Declare your globals
Use an IIFE
Declare your constants
Don’t use special classes
Use native ES6 syntax when possible
  • Watch the linter for other coding standards problems
  • Comment, comment, comment.