---
url: https://plugin.stripo.email/editor-configuration/module-editing-mode.md
---
# Module Editing Mode

:::custom-warning
Plan: **Enterprise** only. Available from v2.67.0.
:::

By default, the Plugin Editor opens **emails** for editing (`entityType: 'email'`). With Module Editing Mode you can launch the same editor to **create or edit a single reusable module** (a stripe, structure, or container) stored in your plugin's module library — without opening a full email.

This lets you use Stripo as a standalone module editor inside your own application: build a "New module" button, an "Edit module" action in your library UI, and let users design modules in the same drag-n-drop editor they already know.

The mode is controlled entirely through initialization parameters. No new permanent UI elements are added to the editor.

:::custom-warning
Module Editing Mode is available on the Enterprise plan only. If the editor is initialized with `entityType: 'module'` on any other plan, it does not initialize and shows a toaster notification signaling that the Enterprise plan is required for this mode.
:::

## **Enabling the Mode ​**

Pass `entityType: 'module'` when initializing the editor:

```js
window.UIEditor.initEditor(domContainer, {
  metadata: { /* ... */ },
  entityType: 'module',
  onTokenRefreshRequest: function (callback) { /* ... */ }
  // + module parameters, see below
});
```

What happens next depends on whether you pass a `moduleId`:

* **`moduleId` provided** → the editor opens that existing module for editing.
* **`moduleId` omitted** → the editor starts creating a new module (`moduleType` is required).

:::custom-warning
If `entityType` is omitted or set to `email`, the editor works in the regular email-editing mode and every parameter on this page is ignored.
:::

## Editing an Existing Module

Pass `moduleId` to open a module that already exists in your library:

```js
window.UIEditor.initEditor(domContainer, {
  metadata: { 
     /* other parameters */
     moduleId: '12345'
  },
  entityType: 'module',
  onTokenRefreshRequest: function (callback) { /* ... */ }
});
```

:::custom-warning
Where to get a `moduleId`: use the [Modules API](/reference/plugin-modules-api) (`GET /api/v1/customblocks/v4/modules/list`) to list the modules that belong to your plugin. It supports filtering by key, category, tags, name, synchronization status, and ID, with pagination — and every returned module includes its `id`, which you pass here. The auth token must have the `API` role.
:::

When `moduleId` is provided:

* Any `html` and `css` passed in the configuration are **ignored** — the module content is loaded from the plugin database.
* The editor validates that the module:
  * is not deleted,
  * belongs to the current `pluginId`,
  * is available for editing.
* If validation fails — the module is not found, deleted, or does not belong to this plugin — **the editor does not initialize** and a toaster notification is shown to the user (see Error handling).

:::custom-warning
When both `moduleId` and `moduleType` are provided, the editor treats it as editing an existing module and ignores `moduleType`.\
The metadata parameters (`moduleName`, `moduleDescription`, `moduleCategoryId`, `moduleTags`) are also ignored when editing an existing module — its existing metadata is preserved.
:::

## Creating a New Module

Omit `moduleId` and pass `moduleType` to start a new module:

```js
window.UIEditor.initEditor(domContainer, {
  metadata: { /* ... */ },
  entityType: 'module',
  moduleType: 'STRUCTURE',      // 'STRIPE' | 'STRUCTURE' | 'CONTAINER'
  key: 'shared-modules',        // optional: target folder storage key
  css: '...',                   // optional: see CSS below
  onTokenRefreshRequest: function (callback) { /* ... */ }
});
```

Rules:

* `moduleType` is **required** and must be one of `STRIPE`, `STRUCTURE`, or `CONTAINER`. If it is missing or invalid, **the editor does not initialize** and a toaster notification is shown (see Error handling).
* `key` (optional) is the storage key of the folder the new module will be saved to — the same **Storage Key ID** you configure for module folders (see Modules Library). If omitted, the first folder the user is allowed to write to is used.
* An empty module of the chosen type is prepared, but it is **persisted only after the first change** to the module content or its metadata (see Saving).

The `html` parameter is **not used** in Module Editing Mode. A new module always starts empty for the chosen `moduleType`; an existing module is always loaded from the database by `moduleId`. Any `html` passed at init is ignored in both cases.

### CSS

* If `css` is provided, it is applied to the new module on creation.
* If `css` is not provided, the editor's default CSS is applied.
* `css` applies only when **creating** a new module; it is ignored when editing an existing module (`moduleId`).

### Initial Metadata for a New Module

When creating a new module you can preset its metadata so the module is saved with the right name, description, category, and tags — without requiring the end user to fill them in manually.

```js
window.UIEditor.initEditor(domContainer, {
  metadata: { /* ... */ },
  entityType: 'module',
  moduleType: 'STRIPE',
  moduleName: 'Promo header',
  moduleDescription: 'Reusable promotional header with CTA',
  moduleCategoryId: 12,
  moduleTags: ['promo', 'header'],
  onTokenRefreshRequest: function (callback) { /* ... */ }
});
```

| Parameter | Type | Default | Description |
| ----- | ----- | ----- | ----- |
| `moduleName` | `string` | `New module` | Name of the new module. Maximum length is **200 characters**; longer values are trimmed to 200. |
| `moduleDescription` | `string` | empty | Description of the new module. Maximum length is **500 characters**; longer values are trimmed to 500. |
| `moduleCategoryId` | `number` | `Uncategorized` | ID of the category assigned to the new module. Silently ignored if the category does not exist or is unavailable for this plugin — initialization is not blocked and no toaster is shown. |
| `moduleTags` | `string[]` | no tags | Tags applied to the new module. |

These parameters apply **only when creating a new module** (when `moduleId` is not provided). If `moduleId` is provided, all four are ignored without error. If a parameter is omitted, the default value above is used.

## Saving

Saving in Module Editing Mode follows your plugin's existing save configuration:

* **Autosave** — if autosave is enabled in your Plugin configuration, it works in module mode too. If it is disabled, only manual saving is available via `window.StripoEditorApi.actionsApi.save()`. See Autosaving.
* **New modules** are written to the library only **after the first change** to the module content or its metadata. Opening the editor and closing it without edits creates nothing.
* The module is stored in Stripo's module database and assigned to your plugin and the target folder key.

The module save callbacks already available in the plugin are supported in this mode:

* `onBeforeModuleSave` — called on save and update, lets you preprocess the module before it is stored.
* `validateModuleSave` — called on save and update, lets you allow or block the operation.

## Module Details Dialog

In Module Editing Mode the module metadata (name, description, category, tags) is edited in a details dialog, similar to account mode. You can open this dialog programmatically — for example, from a "Show module data" button in your own UI:

```js
window.StripoEditorApi.modulesApi.openModuleDetailsDialog();
```

See JavaScript API for the full API surface.

## Limitations

In `entityType: 'module'` mode the following are **not** supported:

* versioning;
* version history;
* simultaneous (collaborative) editing.

The following **work as usual**:

* autosave (when enabled);
* manual saving;
* standard editing logic.

## Compatibility With Other Settings

* `html` passed at init is **always ignored** in this mode (a new module starts empty; an existing module is loaded by `moduleId`).
* `css` is honored **only when creating** a new module and ignored when editing an existing one.
* Version History does not work in Module Editing Mode — version-history controls (e.g. `versionHistoryButtonSelector`) have no effect, because version history is disabled in this mode.
* Email-specific metadata and features (e.g. UTM, email title/preheader) do not apply to modules.
* All other editor configuration — panel position, locale, permissions, image gallery, fonts, etc. — behaves the same as in email mode.

## Error Handling

Errors during initialization are surfaced to the user through the standard toaster. **HTTP error codes (400 / 403) are not returned to the initialization function** — initialization simply does not complete and the user sees a notification.

| Situation | Message |
| ----- | ----- |
| `entityType: 'module'` on a non-Enterprise plan | Editor does not initialize; a toaster notification signals that this mode requires upgrading to the Enterprise plan. |
| Invalid or unavailable `moduleId` (not found, deleted, or not owned by this plugin) | Module not found or unavailable for this plugin |
| Missing or invalid `moduleType` (create mode) | Invalid module type. Allowed values: Stripe, Structure, Container. |

:::custom-warning
To display these messages, your plugin implementation must support notifications. See [Notification Settings](/editor-configuration/commenting#notifications-api).
:::

## Example

```js
// Edit an existing module
window.UIEditor.initEditor(document.getElementById('editor'), {
  metadata: { 
    /* other mandatory parameters */
    moduleId: '8842', 
  },
  entityType: 'module',
  onTokenRefreshRequest: refreshToken
});

// Create a new "structure" module preset with metadata, saved to a specific folder
window.UIEditor.initEditor(document.getElementById('editor'), {
  metadata: { /* ... */ },
  entityType: 'module',
  moduleType: 'STRUCTURE',
  key: 'marketing-modules',
  moduleName: 'Footer · Legal',
  moduleDescription: 'Standard legal footer',
  moduleCategoryId: 8,
  moduleTags: ['footer', 'legal'],
  onBeforeModuleSave: function (data) { return { canSave: true }; },
  validateModuleSave: function (data) { return { canSave: true }; },
  onTokenRefreshRequest: refreshToken
});
```
