Skip to main content

CMS React modules are similar to traditional HubL modules, in that they have fields, can be edited in the content editor, and can be used in drag and drop areas. But the HTML for a React module is generated by a React component instead of HubL, and its fields can be generated with either JSX or JSON.

Below, learn more about building CMS React modules, including required directory structure, defining fields, and working with data.

CMS React modules must be located in the /components/modules subdirectory of your CMS React project. The JavaScript file can either live within that directory or be contained within another directory, using the module name as the file/directory name.

/components/modules/ExampleModule/index.jsx

/components/modules/ExampleModule.jsx

The path will determine how you reference the module in HubL, as shown below.

Whichever path you choose, the file (i.e., either ExampleModule/index.jsx or ExampleModule.jsx) must contain the following named exports:

  • Component: a React component to be rendered. It may contain islands.
  • meta: a JavaScript object, equivalent to the meta.json file in HubL modules.
  • fields: a JSX tree using components from @hubspot/cms-components/fields to define module fields or a traditional JavaScript fields object.

As an example, your index.jsx or ExampleModule.jsx file exports might look similar to the following:

Note that you may use re-exports, as shown in the example index.jsx file below:

Module fields can be expressed as a JSX tree using field components from @hubspot/cms-components/fields. These are the same module fields that HubL modules use. TypeScript definitions are included so that you can benefit from autocomplete and validation when defining fields. You can find all available fields in the fields reference documentation.

You may express field definitions as an array of JavaScript objects identical to the traditional HubL module JSON structure, exporting the same way as fields. However, using JSX syntax is recommended, as it comes with the benefits of improved readability, sharing field logic, and more.

By writing module fields using JSX, you'll benefit from improved readability, along with the ability to dynamically generate fields, share field logic between modules, and create custom abstractions around field definitions.

For example, below is a FullNameField custom field component that abstracts out a group of two or three text fields:

Note that the root component of the fields export must be ModuleFields. Additionally, the above code makes use of FieldGroup, which is the component type that creates the field groups you would use in HubL modules.

In the FullNameField React component for the module fields defined above, props will have the following shape:

Note that the default was used to fill in the value field once it was passed. This is because module values are passed from the server, so if someone changes the value of a field in the page editor, the new value will be passed to your module. But in the above case where no page-level field value is set, the server passes the default value to your props.

In addition to ModuleFields and FieldGroup, another component type from @hubspot/cms-components/fields is RepeatedFieldGroup. It creates a field group repeater, and can be used as shown below:

Field values are passed as props to the Component export of the module. For example, the code below would use the field structure from the previous example inside your module's component:

Like in HubL modules, you can bind a GraphQL data query to a React module to fetch data. The GraphQL integration currently supports querying data from HubDB and custom objects.

Adding a named query export to a module will provide the query result to render in the component props as dataQueryResult. You can import and re-export a .graphql query file or a JavaScript expression that evaluates to a GraphQL query (e.g., with gql-query-builder).

Accessing the data in ModuleComponent is shown below:

Using GraphQL in this way will connect any module and subsequent downstream pages to updates to the query and upstream data. Updates to data sources referenced from the query will cause the page to prerender. Learn more about fetching data.

To explore your account's GraphQL schema and build queries, you can use the GraphiQL tool in your account. Learn more about testing and running queries using GraphiQL.

To automatically attach and pass through HubL context variables to your React modules, you can use the hublDataTemplate API.

First, export a string from your module via hublDataTemplate. In that string, set the hublData variable.

The template will accept any valid HubL, including filters and functions and module field references. The data will come through on your React module as a top level prop of hublData.

While developing modules in cms-dev-server, update the URL to include /preview/ between the port number of your locally running server and the /module/... routes to have your local hublDataTemplate string resolve.

For example: hslocal.net:3000/preview/module/...