Implementation Guidelines


The only <script> tag should be your runtime, and it should be deferred.

Web Components

Web Components are just Custom Elements with superpowers.

Custom Elements are custom HTML elements where the tag name is lowercase, kebab-case, and contains at least 1 hyphen.

When JavaScript is needed, upgrade a Custom Element into a Web Component. Below is a diagram explaining how Custom Elements become Web Components.

Diagram showing a web components upgrade path

How do you load Web Components with only one script tag?

Lazy load the JavaScript. Use the Intersection Observer API to watch the Custom Elements that need to be upgraded and when the Custom Element intersects with the viewport fetch the script or use the dynamic import syntax.

What if I know I’ll need a Web Component right away?

Eager load the JavaScript. Functionally it’s the same as lazy loading except it doesn’t use the Intersection Observer API.


A controller is used to access a model that’s maintained off the main thread. The controller can be accessed by Web Components and other controllers.

Packages and Libraries

Try to limit your use of NPM packages and 3rd party libraries. Use tools like rollup to import the 3rd party code into your project. Don’t assume 3rd party libraries are built to be imported using ES Modules and don’t assume they’ll be easy to implement in your project.


The only <style> or <link rel="stylesheet"> tags should be critical CSS. All other CSS should be lazy loaded.

After the DOMContentLoaded event has fired on the window all lazy loaded stylesheets should be fetched.

Stylesheets hidden behind a user interaction should be fetched when the interaction occurs.


Use a modified version of the Actor Model where not everything is an Actor and Actors can have more than one inbox.

Not all Web Components and controllers are Actors.

Web Components and controllers do not have to be an Actor to send a message.

Continued Reading