> ## Documentation Index
> Fetch the complete documentation index at: https://developers.hubspot.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

---
id: 653605c6-ee61-4452-a32d-997944139f81
---

# Modules

> Learn more about CMS React modules, including how to structure your files and use fields.

CMS React modules are similar to [traditional HubL modules](/cms/start-building/building-blocks/modules/hide-modules-and-sections), in that they have fields, can be edited in the content editor, and can be used in [drag and drop areas](/cms/start-building/building-blocks/drag-and-drop/overview). 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.

## Directory structure

CMS React modules must be located in the `/components/modules` subdirectory of your [CMS React project](/cms/start-building/introduction/react-plus-hubl/project-structure). 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/MyModule/index.jsx`

```hubl theme={null}
projectName/
└── src/
  └── cms-assets/
    └── my-react-assets/
      └── components/
        └── modules/
          └── MyModule/
            └── index.jsx
```

`/components/modules/MyModule.jsx`

```shell theme={null}
projectName/
└── src/
  └── cms-assets/
    └── my-react-assets/
      └── components/
        └── modules/
            └── MyModule.jsx
```

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

```hubl theme={null}
// ExampleModule/index.jsx
{% module "ExampleModule"
  path="@projects/your-project/js-package/components/modules/MyModule",
%}

// ExampleModule.jsx
{% module "ExampleModule"
  path="@projects/your-project/js-package/components/modules/MyModule.jsx",
%}
```

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

* `Component`: a React component to be rendered. It may contain [islands](/cms/reference/react/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.

```shell theme={null}
// Directory Structure for module-as-directory

└── components/
  └── modules/
    └── ExampleModule/
      ├── ExampleModuleFields.jsx
      ├── ExampleModuleComponent.jsx
      ├── ExampleModuleMeta.js
      └── index.jsx
```

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

```jsx theme={null}
import { ModuleFields, TextField } from '@hubspot/cms-components/fields';
import footerStyles from '../../../styles/footer.module.css';

export function Component({ fieldValues }: any) {
  return (
    <footer className={footerStyles.footer}>
      <p>{fieldValues.footerText}</p>
    </footer>
  );
}

export const fields = (
  <ModuleFields>
    <TextField label="Footer Text" name="footerText" default="Be Well." />
  </ModuleFields>
);

export const meta = {
  label: 'Footer Module',
};
```

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

```jsx theme={null}
// Note: index.js re-exports ExampleModuleFields.jsx,
// ExampleModuleMeta.js, and ExampleModuleComponent.jsx
// as named exports

export { default as Component } from "./ExampleModuleComponent.jsx";
export { fields } from "./ExampleModuleFields.jsx";
export { meta } from "./ExampleModuleMeta.js";
```

## Module fields

Module fields can be expressed as a JSX tree using field components from `@hubspot/cms-components/fields`. These are the same [module fields](/cms/reference/fields/module-theme-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](/cms/reference/fields/module-theme-fields).

You may express field definitions as an array of JavaScript objects identical to the traditional HubL module [JSON structure](/cms/reference/fields/module-theme-fields), 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.

### Building fields with JSX

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:

```jsx theme={null}
import {
  ModuleFields,
  TextField,
  FieldGroup,
  BooleanField
} from '@hubspot/cms-components/fields';

const FullNameField = ({ includeMiddleName = false }) => (
  <FieldGroup
    name="full_name"
    label="Full Name"
>
    <TextField
      name="given_name"
      label="Given Name"
      default="HubSpot"
      required={true}
    />
    {includeMiddleName && (
      <TextField
        name="middle_name"
        label="Middle Name"
        default=""
      />
    )}
    <TextField
      name="family_name"
      label="Family Name"
      default="Developer"
    />
  </FieldGroup>
);

export const fields = (
  <ModuleFields>
    <TextField
      name="example_field"
      label="Example Text Field"
      default="Placeholder text" />

    <FieldGroup name="group_of_fields" label="Field Group">
      <BooleanField
        name="child_boolean_field"
        label="Child Boolean Field"
        default={true}
      />
      <TextField
        name="child_text_field"
        label="Child Text Field"
        default="Child Field"
      />
    </FieldGroup>


    {/*Using the custom field component alongside other fields*/}
    <FullNameField includeMiddleName={false}>
  </ModuleFields>
);
```

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](/cms/reference/fields/overview#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:

```jsx theme={null}
// FullNameField module field props
{
  example_field: "Placeholder text",
  group_of_fields: {
    child_boolean_field: true,
    child_text_field: "Child Field"
  },
  full_name: {
    given_name: "HubSpot",
    family_name: "Developer",
  }
}
```

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.

### Repeated field groups

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:

```jsx theme={null}
export const fields = (
  <ModuleFields>
    <RepeatedFieldGroup
      name="default_todos"
      label="Default Todos"
      occurrence={{
        min: 1,
        max: 500,
        default: 1,
      }}
      default={[
        {
          text: "Todo Test 1a",
          completed: false,
        },
        {
          text: "Todo Test 2",
          completed: true,
        },
      ]}
    >
      <TextField label="Todo title" name="text" default="Todo..." required />
      <BooleanField label="Todo Completed" name="completed" default={false} />
    </RepeatedFieldGroup>
  </ModuleFields>
);
```

### Using field values

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:

```jsx theme={null}
export const Component = ({ fieldValues }) => {
  return (
    <ul>
      <li>{fieldValues.example_field}</li>
      <li>{fieldValues.group_of_fields.child_text_field}</li>
    </ul>
  );
};
```

## GraphQL

Like in HubL modules, you can [bind a GraphQL data query](/cms/start-building/features/data-driven-content/graphql/query-hubspot-data-using-graphql) to a React module to [fetch data](/cms/start-building/introduction/react-plus-hubl/data-fetching). 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](https://www.npmjs.com/package/gql-query-builder)).

```jsx theme={null}
// index.js

import ModuleComponent from "./ModuleComponent.js";
import ModuleFields from "./ModuleFields.js";
import ModuleMeta from "./ModuleMeta.js";
import myQuery from "./myQuery.graphql";

// This component will receive the query result via `dataQueryResult`
export const Component = ModuleComponent;
export const meta = ModuleMeta;
export const fields = ModuleFields;
export const query = myQuery;
```

Accessing the data in `ModuleComponent` is shown below:

```jsx theme={null}
//ModuleComponent.jsx

export default function ModuleComponent(props) {
  return (
    <div>
      <span>{props.dataQueryResult.data.CRM.contact_collection.items[0].firstname}</span>
      <span>{props.dataQueryResult.data.CRM.contact_collection.items[0].lastname}</span>
    </div>
  );
}
```

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](/cms/start-building/introduction/react-plus-hubl/data-fetching).

To explore your account's GraphQL schema and build queries, you can use the [GraphiQL](http://app.hubspot.com/l/graphiql) tool in your account. Learn more about [testing and running queries using GraphiQL](/cms/start-building/features/data-driven-content/graphql/query-hubspot-data-using-graphql#test-and-run-queries-interactively-using-graphiql).

## Passing HubL data

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.

```jsx theme={null}
export const hublDataTemplate = `{% set hublData = "Hello from HubL!" %}`;
```

The template will accept any valid HubL, including [filters](/cms/reference/hubl/filters) and [functions](/cms/reference/hubl/functions) and [module field references](/cms/reference/fields/module-theme-fields). The data will come through on your React module as a top level prop of `hublData`.

```jsx theme={null}
import ModuleFields from "./ModuleFields.js";
import ModuleMeta from "./ModuleMeta.js";

export function Component(props) {
  return (
    <div>
      <div>My total posts: {props.hublData.totalBlogPostCount}</div>
      <a href={props.hublData.blogAllPostsUrl}>View all posts</a>
    </div>
  );
}

export const meta = ModuleMeta;
export const fields = ModuleFields;
export const hublDataTemplate = `
  {% set blogId = module.blog_field %}
  {% set hublData = {
      "totalBlogPostCount": blog_total_post_count(blogId),
      "blogAllPostsUrl": blog_all_posts_url(blogId)
    }
  %}
`;
```

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/...`
