Appearance
All events bubble from the <email-builder> element. Use addEventListener or framework equivalents.
eb:save
Fired when the user clicks Save or when builder.save() is called programmatically.
js
builder.addEventListener('eb:save', (e) => {
const { json } = e.detail; // BlockTree
await saveToDatabase(json);
});e.detail field | Type | Description |
|---|---|---|
json | BlockTree | The full block tree at the time of save |
eb:export
Fired when the user clicks Export HTML (Pro+ plan). Receives compiled, email-client-safe HTML.
js
builder.addEventListener('eb:export', (e) => {
const { html } = e.detail; // string
await sendWithSendGrid({ html, to: recipient });
});e.detail field | Type | Description |
|---|---|---|
html | string | Compiled HTML ready to send via any ESP |
eb:error
Fired when a recoverable error occurs (compilation failure, save failure, load failure).
js
builder.addEventListener('eb:error', (e) => {
const { code, message } = e.detail;
showToast(`Editor error: ${message}`, 'error');
});e.detail field | Type | Description |
|---|---|---|
code | string | One of: COMPILE_FAILED, SAVE_FAILED, LOAD_FAILED, EXPORT_FAILED |
message | string | Human-readable description |
Using callbacks instead
You can pass the same handlers as callbacks in updateConfig — use whichever style fits your framework:
js
builder.updateConfig({
onSave: (json) => saveToDatabase(json),
onExport: (html) => sendEmail(html),
onClose: () => router.back(),
});Both the DOM event and the callback fire — you don't need to choose one.
React example
jsx
import { useRef, useEffect } from 'react';
import '@maillune/sdk';
export function EmailEditor({ userId, onSave }) {
const ref = useRef(null);
useEffect(() => {
const el = ref.current;
const handler = (e) => onSave(e.detail.json);
el.addEventListener('eb:save', handler);
return () => el.removeEventListener('eb:save', handler);
}, [onSave]);
return (
<div style={{ height: 700 }}>
<email-builder ref={ref} api-key={process.env.MMS_API_KEY} user-id={userId} />
</div>
);
}