Need a solution for implementing recurring global modules using CMS React

Hello! I’m a solo developer that’s fairly new to HubSpot and I’m still learning how to develop themes and figuring out what’s the best practices/workflow to use HubSpot for my work.

I’ve created 2 different themes using the CMS React framework and it has been a great experience so far.

However I realised that I have common global modules that are exactly the same within the 2 different themes (eg. the header and footer). As such, it’s quite a repetitive experience to populate these modules on the 2 separate themes, which gets tedious when my team have to populate them with content for 8 different languages.

I would like to seek advice on how to make it easier to populate content in this scenario (i.e. if I were to create a new theme for my next project, the header and footer with content from all languages will be already pre-populated)

I have a few solutions in mind, but I don’t know how feasible these options are:

  1. Create a “master” theme that can be cloned (along with the modules) and modified using a “child” theme (currently not possible, as cloning or creating child theme of a theme in @projects throws me a generic error and I’m not sure why this happens)
  2. Maintain a single theme that will be used on all my websites (sounds like it will be very bloated and difficult to maintain over time)
  3. Access previously created modules by directing it to the path eg. @projects/my-theme-name/theme/components/modules/header.tsx (not sure how, as my CMS React modules do not show up in the Design Manager when i search for it)
  4. Create standalone global modules that isn’t tied to a theme so they can be used everywhere. (Not sure how to create with CMS React)

Will greatly appreciate any solutions or thoughts. CMS React solutions will be preferred!

Thank you!

Hey @creative.tech,

personally I’m not the biggest CMS React friend as it’s far from being a true HubL replacement right now

Regardless of my personal opinion, here a few ideas/good-to-know things:

If you’re looking for an easy solution for non-devs like cloning and managing (child-)themes on their own, you’ll need to drop the CMS React approach and create HubL themes as they’re visible & accessible via the Design-Manager. Amazing for non-devs who don’t have a local dev environment set up.

You’ve already going in the right direction with the child-theme approach - please note that there are limitations on how many child-themes you can have per tier&portal.

As a child-theme inherits all parent theme settings (theme fields.json/fields.js)by default, it’s easier to put all the required global styles into this file and therefore have a cleaner code.

For elements which aren’t supported in the theme fields.json file (i.e text), you can create a super simple variables.html file and put the individual variables in it. Once done, load this file in a template/module and use it - You’ve created your own “variable dictionary” :slight_smile:

Example:

<!--
    templateType: none
    label: variables
    isAvailableForNewContent: false
-->
    
{% set button_label = "Click me" %}
{% set button_aria = "Click this button" %}

In a template it would look like this:

<!--
    templateType: page
    label: Some Page label
    isAvailableForNewContent: true
-->
    
{%- include "path/to/variables.html" -%}

...

<a href="#" aria-label="{{ button_aria }}">{{ button_label }}</a>

...

Since you’re working with a multi-language setup, I highly recommend to check out the @hubspot/cmsdefaultsystempages folder (especially the system pages as they got the translation setup).

In a nutshell it’s pretty straight forward:

  • create a “_locales” folder somewhere in your theme
  • add lang_name folders like “de”, “en”, “en_gb”… to it
  • add a messages.json into each folder (only possible via local setup)
  • write the translated variables/values as JSON into it
  • Add the auto-translation detection code into each template which should use those translations (see example below)
  • done
{% set template_translations = load_translations("path/to/_locales-folder", html_lang, "de") %}

the “de” in this code is what defines the default language.

setup one In terms of global modules for header & footer - from experience I’d say that, while those elements can be done as global modules, you might want to check out the global partials approach.

Another great approach to manage and populate content globally is HubDB. Simply create a HubDB per language & usecase (i.e products) and put the row data into the templates.
While, you technically could also create a if-statement to check for the page language and switch automatically between the individual HubDBs - I don’t recommend this as it would be always the same page URL (which is not the best solution in most cases).
What I rather recommend doing is creating a simple (global) module with a HubDB selector, and use the export_to_template_context variable to grab the module settings directly on template level (or modify the template based on the module settings.

Hope this helps.

Let me know if you got further questions.

best,

Anton

Hey Anton,

Thank you so much for the detailed answer, it’s very helpful.

  1. HubL setup for non-devs: That’s a good tip, thanks for the suggestion! It will definitely help my company in the long run, I’ll see how I can do that in the near future. For now, I work a lot faster with React and the team seems to be doing ok without touching the themes directly.
  2. Child theme setup & Global Partials: yep I understand the limitations. It seems like this might not be the best approach for my case as I’m more concerned about global content than global styles/variables. Though I will give it a try still just to understand it a bit better. The variables setup is pretty neat, thanks for sharing!
  3. System translation files: That seems like a possible solution! I’ll give that a shot. Does that mean the content will be hard coded into the translation files, and users have to edit the files to change the content if there are any updates.
  4. HubDB: This seems like a feasible solution for me! I’ll give this a try.

I’ll update if there are any further questions, tysm :slight_smile:

P.S. I just read a similar topic recommended for my post, and the solution worked for me even though I couldn’t search for the file in my Design Manager (my original post, point 3) which makes it hard for me to know if it would have worked or not. For someone looking for the same solution, the path to the file would be @projects/[theme-folder-name]/[theme-uid]/modules/[ComponentName.tsx]. Thank you too, Barry.

I’ll still work around the different solutions to see what’s the best for me.

oops the path should be @projects/[theme-folder-name]/[theme-uid]/components/modules/[ComponentName.tsx]

Hey @creative.tech,

for the translation files: Yes - the content would be hardcoded.

A different approach would be to create global modules, put them onto any page (can be a “blank” template), hit edit and add translations to them directly in HubSpot. This will store the value(s) in a non-accessible space of HubSpot, but would allow non-devs manage content of this particular content globally.

If you want to have it less hardcoded and easier for non-devs to manage, give the export_to_template_context a shot.
Used it in a recent project where I’ve created a configuration module with it.

Result:
The user can modify the non drag&drop template to his needs on a page level. The module contains many text, boolean and media fields like forms, video, images…
Depending on what the user chooses, he get’s the depending fields and those values are being put into the template.
Pretty neat :slight_smile:

Code example:

...
{% module 'event_config' path="path/to/module" label="Event configuration", export_to_template_context=true %}
...
<div class="event-registration-form dark" id="registration">
   <script src="https://js-eu1.hsforms.net/forms/embed/developer/{{ hub_id }}.js" defer>/script>
   <div class="hs-form-html" data-region="eu1" data-form-id="{{ widget_data.event_config.event_registration_form.form_id }}" data-portal-id="{{ hub_id }}"> 
   </div>
</div>
...

(using the {{ hub_id }} variable is great if you’re developing in a test account and move it to prod later as you don’t need to manually edit the template :wink: )