Modules
Save rows as reusable modules that appear in the Modules Library accordion for drag-and-drop insertion.
Module categories are canonicalized to lowercase by the SDK and editor. For example, "Banner", "banner", and "BANNER" are treated as the same banner category. The editor displays category labels with capitalized styling in the UI.
- React
- Vue
- Angular
- Vanilla JS
import { useRef } from "react";
import { DragbleEditor, DragbleEditorRef } from "dragble-react-editor";
function ModuleEditor() {
const editorRef = useRef<DragbleEditorRef>(null);
const handleReady = async () => {
const editor = editorRef.current?.editor;
editor?.setModules([
{
id: "hero-banner",
name: "Hero Banner",
category: "Banner", // normalized to "banner"
mode: "email",
type: "standard",
thumbnail: "https://cdn.example.com/thumbs/hero.png",
data: heroRowJson, // saved row JSON
},
{
id: "footer-standard",
name: "Standard Footer",
category: "footer",
mode: "email",
type: "standard",
thumbnail: "https://cdn.example.com/thumbs/footer.png",
data: footerRowJson,
},
]);
};
return (
<DragbleEditor
ref={editorRef}
editorKey="db_your_key"
editorMode="email"
onReady={handleReady}
onModuleSave={async (module) => {
await fetch("/api/modules", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(module),
});
}}
onModuleDelete={async (module) => {
const response = await fetch(`/api/modules/${module.id}`, {
method: "DELETE",
});
return response.ok
? { success: true }
: { success: false, error: "Failed to delete module" };
}}
/>
);
}
<template>
<DragbleEditor
ref="editorRef"
editor-key="db_your_key"
editor-mode="email"
@ready="onReady"
@module-save="onModuleSave"
/>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { DragbleEditor } from "dragble-vue-editor";
const editorRef = ref<InstanceType<typeof DragbleEditor>>();
async function onReady() {
editorRef.value?.setModules([
{
id: "hero-banner",
name: "Hero Banner",
category: "Banner",
mode: "email",
type: "standard",
thumbnail: "https://cdn.example.com/thumbs/hero.png",
data: heroRowJson,
},
]);
}
async function onModuleSave(module: any) {
await fetch("/api/modules", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(module),
});
}
</script>
import { Component, ViewChild } from "@angular/core";
import { DragbleEditorComponent } from "dragble-angular-editor";
import type { DragbleSDK, ModuleSaveData } from "dragble-types";
@Component({
selector: "app-module-editor",
standalone: true,
imports: [DragbleEditorComponent],
template: `
<dragble-editor
#editor
editorKey="db_your_key"
editorMode="email"
(ready)="onReady($event)"
(moduleSave)="onModuleSave($event)"
></dragble-editor>
`,
})
export class ModuleEditorComponent {
@ViewChild("editor") editorComp!: DragbleEditorComponent;
private sdk: DragbleSDK | null = null;
async onReady(sdk: DragbleSDK) {
this.sdk = sdk;
this.sdk.setModules([
{
id: "hero-banner",
name: "Hero Banner",
category: "Banner",
mode: "email",
type: "standard",
data: heroRowJson,
},
]);
}
async onModuleSave(module: ModuleSaveData) {
await fetch("/api/modules", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(module),
});
}
}
dragble.init({
containerId: "editor-container",
editorKey: "db_your_key",
editorMode: "email",
callbacks: {
onReady: async () => {
dragble.setModules([
{
id: "hero-banner",
name: "Hero Banner",
category: "Banner",
mode: "email",
type: "standard",
thumbnail: "https://cdn.example.com/thumbs/hero.png",
data: heroRowJson,
},
]);
},
onModuleSave: async (module) => {
await fetch("/api/modules", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(module),
});
},
onModuleDelete: async (module) => {
const response = await fetch(`/api/modules/${module.id}`, {
method: "DELETE",
});
return response.ok
? { success: true }
: { success: false, error: "Failed to delete module" };
},
},
});
:::tip Module row JSON
A module's data property contains the saved row JSON. When a user saves a row through the editor, onModuleSave returns the row data, rendered html, generated thumbnail, mode, type, and normalized lowercase category.
:::
Modules Library configuration​
Configure the Modules Library accordion under options.appearance.sidePanel.modulesTab.modulesLibrary:
dragble.init({
containerId: "editor-container",
editorKey: "db_your_key",
options: {
appearance: {
sidePanel: {
modulesTab: {
modulesLibrary: {
visible: true,
defaultExpanded: true,
title: "Brand Modules",
categories: ["Banner", "POPULAR", "footer"],
defaultCategory: "Banner",
},
},
},
},
},
});
The SDK/editor stores those categories as banner, popular, and footer. The Modules Library dropdown displays them capitalized.
Synced modules​
Synced modules stay linked to the source. When you update a synced module, all designs using it reflect the changes on next load:
dragble.setModules([
{
id: "legal-footer",
name: "Legal Footer",
category: "footer",
mode: "email",
type: "synced", // Changes propagate to all designs using this module
data: legalFooterRowJson,
},
]);
:::warning Synced module edits Users cannot edit the content of a synced module inline. They must update the source module. Unsynced modules are fully editable after insertion. :::
Method reference​
| Method | Returns | Description |
|---|---|---|
setModules(modules) | void | Replace the available modules list. Categories normalize lowercase. |
addModule(module) | void | Append a single module to the panel. |
removeModule(id) | void | Remove a module by ID. |
Delete callback​
When the user deletes a module from the Modules Library, the editor calls onModuleDelete with the module metadata:
interface ModuleDeleteData {
id: string;
name?: string;
category?: string;
type?: "standard" | "synced";
mode?: "email" | "web";
}
Return { success: true } to confirm the delete. If you return { success: false, error }, the editor keeps the module in the library.
Next steps​
- Header & Footer — lock rows as non-editable header/footer
- Custom Tools — build custom tools to use within modules
- Load & Save Designs — persist designs that reference modules