Modules BETA

Table of contents

Transitioning from V1 to V2 modules

This page is designed to give experienced custom module developers quick answers to common questions regarding the differences between version 1 custom modules and the new module framework (referred to here as v1 and v2). These changes have been made alongside a number of significant additions to the module framework that provide more robust and reliable options for building complex functionality. In the following sections, we’ll highlight the changes that are most likely to affect experienced developers and provide recommended approaches to a couple of common v1 patterns that will no longer be supported.

Using CSS/JS

V1 modules did not have a very prescriptive approach to CSS and JS. Developers used a combination of techniques, loading code via require_js and require_css as well as many functions and tags that are no longer supported. For a full list of unsupported tags, please see the reference section.

V2 modules have a very prescriptive approach to CSS and JS. With the exception of custom modules for email use, all custom modules now have CSS and JS editor sections.

HubSpot Help article screenshot

Any CSS and JS that is specific to a module should be written in these sections of the editor. This code is minified and included in the head and foot of the served page. JS is also wrapped in a closure for namespacing.

If a module requires a library or other external assets, you should use the Linked Files section of the inspector.

HubSpot Help article screenshot

CSS and JS files included via Linked Files will automatically be loaded on pages using the module. Other assets, such as images will be copied from portal to portal with your module, but will only be loaded if and when they are referenced in your code (i.e. background images in CSS). When referencing these files, you should use the module_asset_url function, as illustrated below.

    background: url({{ module_asset_url('arrow.png') }});

Please note that this function is the ONLY HubL that can be placed in the CSS and JS sections of the editor. In the sections below we outline some solutions for scenarios when you might feel the need to use HubL in these sections.

To avoid any unexpected conflicts or dependency errors, please familiarize yourself with the order of execution for CSS and JS files:

The order of JavaScript includes are:

  1. external_js
  2. js_assets (in order)
  3. module js
  4. JS inside the HubL markup within a require_js block.

The order of CSS includes are:

  1. css_assets
  2. module css

CSS inside the HubL markup within a require_css block.

Using JS plugins

The order of JavaScript includes detailed above should provide you with a good reference for organizing the code in your module. Typically if you’re using a 3rd party script, you will link the script file via the Linked files section of the inspector. Then you can instantiate the plugin in the JS section of the code editor. If you need to pass parameters to the plugin, you can use data attributes in the HTML + HUBL section of the editor to store these values. The screenshot below contains a pseudo code example.

HubSpot Help article screenshot

Note: It is also possible to instantiate modules in the HTML + HUBL section if you prefer to pass HubL directly to your script. However, keep in mind that the script in the JS section of the editor is wrapped in a closure and will not be in the same namespace as script written in the HTML + HUBL section.

Using HTML/HubL

Rich text modules no longer support code view. Editors modifying WYSIWYG code is the achilles heel of any CMS that allows this behavior. It is invariably the most common source of bugs and confusion. One of the central goals of building a new module framework was to provide stable and scalable options for accomplishing tasks that were being clumsily relegated to the WYSIWYG editor either out of necessity or carelessness.

HTML and HubL modules have been removed. These modules provided a quick way for developers to add snippets of HTML and HubL to a template. Unfortunately, they tend to make templates difficult to understand and edit. As part of a larger effort to make templates more predictable and maintainable, we’ve removed these modules in favor of keeping all code inside the context of custom modules.

Inevitably, any time features are sunsetted there will be pain points for users. What follows is an attempt to address as explicitly as possible the most common examples of using code outside of a module. There are infinite flavors of these examples, but the overall techniques should be recognizable. 

Small snippets of HTML/JS

This is especially common in rich text modules. Code such as embed scripts get pasted in between text and a video gets rendered more or less correctly. Except when it doesn’t. A custom module is a much better solution for the vast majority of these scenarios.

In the example shown below, the developer has created a module with 3 fields, two of which have defaults to allow a user to quickly and reliably embed a YouTube video. As opposed to requiring a user to paste embed code into a rich text module, this method gives the developer full control of the markup.

HubSpot Help article screenshot
The screenshot below shows the editing experience for this module. When the site editor goes to embed a YouTube video, they have all the options they need, and no ambiguity or room for error. The developer can also add help text and field validation to further improve the editing experience. Details on these techniques can be found here.
HubSpot Help article screenshot

HTML tables in emails

Up until now, it has been difficult to provide clients with expandable content areas with specific markup, especially in emails where flex columns are/were not available. Now that the new module framework allows you to create repeating fields and groups of fields, what was once impossible is now trivial.

In the example shown below, the developer has created two rich text fields named Column 1 and Column 2 and then grouped them and named the group Row. They then enabled Repeater options for the Row group.

With the fields configured this way, the developer looped through each row and plugged the column data into table cells. This example is extremely simple for the sake of clarity, but this technique can be extended and refined to give editors broad control over very complex layouts while maintaining developer control over every aspect of the markup.

More info on repeating and looping can be found here.

More info on groups can be found here.

HubSpot Help article screenshot