Dragble config
Configure the Dragble editor appearance, features, merge tags, special links, fonts, localization, display conditions, collaboration, branding colors, and editor behavior.From its SKILL.md
npx -y skills add Dragble/dragble-skills --skill dragble-configAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
29.5 KB, ~7.9k tokens by cl100k_base, as published. Nobody here has run it
Dragble Editor Configuration
Overview
All editor configuration is passed through the options object in dragble.init(). The top-level DragbleConfig controls boot-time settings (container, auth, mode), while options holds all runtime-configurable settings (appearance, tools, features, localization, merge tags, etc.).
dragble.init({
containerId: 'editor-container',
editorKey: 'ek_xxx',
editorMode: 'email',
options: {
appearance: { theme: 'light', accentColor: 'indigo' },
features: { preview: true, undoRedo: true },
tools: { video: { enabled: false } },
locale: 'en-US',
// ... all other config
},
});
DragbleConfig (Top Level)
| Property | Type | Required | Description |
|---|---|---|---|
containerId | string | Yes | DOM element ID where the editor iframe is mounted |
editorKey | string | Yes | Project editor key for authentication (ek_...) |
editorMode | 'email' | 'web' | 'popup' | No | Builder type. Default: 'email' |
designMode | 'edit' | 'live' | No | 'edit' = admin mode (shows Row Actions), 'live' = end-user mode (enforces row permissions). Default: 'live' |
design | DesignJson | null | No | Initial design JSON. null = blank design, undefined = no design loaded |
popup | PopupConfig | No | Popup builder config (only relevant when editorMode is 'popup') |
callbacks | DragbleCallbacks | No | Event callbacks (onReady, onChange, onLoad, onError, onModuleSave, onPreview, onContentDialog, etc.) |
options | EditorOptions | No | All editor configuration (appearance, tools, features, locale, merge tags, etc.) |
editorUrl | string | No | Custom editor source URL for enterprise self-hosted editors |
editorVersion | 'stable' | 'latest' | string | No | Editor version to load. Default: 'latest'. Ignored when editorUrl is set |
environment | 'production' | 'development' | 'staging' | No | Environment mode |
dragble.init({
containerId: 'editor',
editorKey: 'ek_live_abc123',
editorMode: 'email',
designMode: 'live',
design: savedDesignJson,
callbacks: {
onReady: () => console.log('Editor ready'),
onChange: (data) => console.log('Design changed', data),
},
options: { /* ... */ },
});
Appearance
Theme
The editor supports 4 themes. Branded themes ignore accentColor.
| Theme | accentColor | Description |
|---|---|---|
'light' | Customizable | Generic light theme, accent tints the UI |
'dark' | Customizable | Generic dark theme, accent tints the UI |
'dragble-light' | IGNORED (fixed indigo) | Dragble branded light theme |
'dragble-dark' | IGNORED (fixed white-on-black) | Dragble branded dark theme |
CORRECT:
options: {
appearance: {
theme: 'light',
accentColor: 'teal', // Works — generic theme respects accentColor
}
}
WRONG:
options: {
appearance: {
theme: 'dragble-light',
accentColor: 'teal', // IGNORED — branded themes use fixed colors
}
}
Accent Colors
24 Radix UI color scale names:
gray, gold, bronze, brown, yellow, amber, orange, tomato, red, ruby, crimson, pink, plum, purple, violet, iris, indigo, blue, cyan, teal, jade, green, grass, mint, sky
Side Panel
options: {
appearance: {
sidePanel: {
tabs: {
content: { visible: true }, // CONTENT tab (tools)
modules: { visible: true }, // MODULES tab (rows + custom tabs)
styles: { visible: true }, // STYLES tab (body settings)
},
modulesTab: {
rows: { visible: true, defaultExpanded: true },
modulesLibrary: {
visible: true,
defaultExpanded: false,
title: 'My Modules',
categories: ['Banner', 'footer', 'header'], // Filter/order displayed categories (optional)
defaultCategory: 'Banner', // Pre-selected category (optional)
},
customTabs: [
{ id: 'snippets', label: 'Snippets', content: '...', icon: 'star', order: 1, visible: true }
],
},
stylesTab: {
general: { visible: true, defaultExpanded: true },
fonts: { visible: true, defaultExpanded: false },
contentAlignment: { visible: true },
backgroundImage: { visible: true },
linkStyles: { visible: true },
preheader: { visible: true },
},
dock: 'right', // 'left' | 'right' (default: 'right')
width: 380, // Panel width in pixels (default: 380)
collapsible: false, // Whether panel can be collapsed (default: false)
accordionsCollapsed: false, // Start all accordions collapsed (default: false)
},
}
}
Action Bar
options: {
appearance: {
actionBar: {
placement: 'top_left', // 'top_left' | 'top_right' | 'bottom_left' | 'bottom_right'
compact: false, // Smaller buttons when true
},
}
}
Shortcut Bar
options: {
appearance: {
shortcutBar: {
placement: 'top_left', // 'top_left' | 'top_right' | 'bottom_left' | 'bottom_right'
},
}
}
Custom Loader
Priority: svg > url > html + css > default spinner.
options: {
appearance: {
loader: {
svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><circle cx="25" cy="25" r="20" fill="none" stroke="#6366f1" stroke-width="4"><animateTransform attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="1s" repeatCount="indefinite"/></circle></svg>',
// OR
url: 'https://example.com/loader.gif',
// OR
html: '<div class="my-loader">Loading...</div>',
css: '.my-loader { color: #6366f1; font-size: 18px; }',
},
}
}
Branding Colors
Set brand colors for all color pickers in the editor at runtime:
// Simple flat array
dragble.setBrandingColors({
colors: ['#FF0000', '#00FF00', '#0000FF', '#FFAA00'],
defaultColors: true, // show default palette below brand colors (default: true)
});
// Named palettes
dragble.setBrandingColors({
colors: [
{ id: 'primary', label: 'Primary', colors: ['#6366f1', '#4f46e5', '#4338ca'], default: true },
{ id: 'secondary', label: 'Secondary', colors: ['#f59e0b', '#d97706', '#b45309'] },
],
defaultColors: false, // hide default palette
});
Runtime
dragble.setAppearance({ theme: 'dark', accentColor: 'violet' });
Feature Flags
Feature flags live in options.features. All are optional.
| Feature | Type | Default | Description |
|---|---|---|---|
preview | boolean | true | Show preview button |
undoRedo | boolean | true | Show undo/redo buttons |
responsiveDesign | boolean | true | Show responsive design view toggles (desktop/mobile) |
imageEditor | boolean | undefined | Enable inline image editor. false = force disable even if plan allows |
audit | boolean | false | Enable template audit trail |
stockImages | boolean | StockImagesConfig | true | Stock images in file manager. false = hide even if plan allows |
userUploads | boolean | true | Enable user image uploads |
fileManager | boolean | true | Show File Manager modal. false hides "Choose Image" button but keeps direct upload |
smartMergeTags | boolean | false | Enable smart merge tag suggestions |
specialLinks | boolean | true | Show special links in text toolbar |
languageSelector | boolean | true | Show language dropdown in side panel. false = language controlled via SDK only |
preheaderText | boolean | true | Show preheader text input in Styles panel (email mode only) |
amp | boolean | false | Enable AMP for Email (email mode only). Unlocks interactive tools |
modules | boolean | ModuleFeaturesConfig | false | Enable Modules Library (save row as module, synced modules). Not available in contentType: 'module' |
header | boolean | false | Enable locked header row from SDK. Requires plan permission |
footer | boolean | false | Enable locked footer row from SDK. Requires plan permission |
dynamicImage | boolean | undefined | Enable dynamic image merge tag on image tool (Business+ plans) |
collaboration | boolean | CollaborationFeaturesConfig | false | Team collaboration (commenting, reviewer role). See Collaboration |
export | ExportFeaturesConfig | all true | Granular export toggles: { html, json, image, pdf, zip } |
options: {
features: {
preview: true,
undoRedo: true,
responsiveDesign: true,
imageEditor: true,
audit: true,
stockImages: { enabled: true, safeSearch: true, defaultSearchTerm: 'business' },
userUploads: true,
fileManager: true,
smartMergeTags: false,
specialLinks: true,
languageSelector: true,
preheaderText: true,
amp: false,
modules: { saveRowAsModule: true },
header: false,
footer: false,
dynamicImage: true,
collaboration: true,
export: { html: true, json: true, image: true, pdf: true, zip: true },
}
}
Merge Tags
Merge tags are dynamic content placeholders (e.g., {{first_name}}) that users can insert into text.
MergeTagsConfig
interface MergeTagsConfig {
excludeDefaults?: boolean; // Hide built-in tags, show only custom (default: false)
sort?: boolean; // Sort alphabetically
customMergeTags?: (MergeTag | MergeTagGroup)[];
}
interface MergeTag {
label: string; // Display label in dropdown
value: string; // Value inserted (e.g., '{{first_name}}')
category?: string; // Optional grouping category
sample?: string; // Preview sample value
}
interface MergeTagGroup {
name: string; // Group name
mergeTags: (MergeTag | MergeTagGroup)[]; // Nested tags
}
Flat Example
options: {
mergeTags: {
customMergeTags: [
{ label: 'First Name', value: '{{first_name}}', sample: 'Jane' },
{ label: 'Last Name', value: '{{last_name}}', sample: 'Doe' },
{ label: 'Email', value: '{{email}}', sample: '[email protected]' },
],
}
}
Grouped Example
options: {
mergeTags: {
excludeDefaults: true,
customMergeTags: [
{
name: 'Contact Info',
mergeTags: [
{ label: 'First Name', value: '{{contact.first_name}}', sample: 'Jane' },
{ label: 'Last Name', value: '{{contact.last_name}}', sample: 'Doe' },
],
},
{
name: 'Company',
mergeTags: [
{ label: 'Company Name', value: '{{company.name}}', sample: 'Acme Inc' },
{ label: 'Website', value: '{{company.website}}', sample: 'https://acme.com' },
],
},
],
}
}
Runtime
dragble.setMergeTags({
customMergeTags: [
{ label: 'Coupon Code', value: '{{coupon_code}}', sample: 'SAVE20' },
],
});
const tags = await dragble.getMergeTags();
Special Links
Special links add custom link categories to the link picker in the text editor toolbar.
SpecialLinksConfig
interface SpecialLinksConfig {
excludeDefaults?: boolean;
customSpecialLinks?: (SpecialLink | SpecialLinkGroup)[];
}
interface SpecialLink {
name: string; // Display name
href: string; // Link href value
target?: '_blank' | '_self' | '_parent' | '_top';
}
interface SpecialLinkGroup {
name: string; // Group name
specialLinks: SpecialLink[];
}
Flat Example
options: {
specialLinks: {
customSpecialLinks: [
{ name: 'Unsubscribe', href: '{{unsubscribe_url}}', target: '_blank' },
{ name: 'View in Browser', href: '{{webview_url}}', target: '_blank' },
{ name: 'Manage Preferences', href: '{{preferences_url}}', target: '_blank' },
],
}
}
Grouped Example
options: {
specialLinks: {
excludeDefaults: true,
customSpecialLinks: [
{
name: 'Email Actions',
specialLinks: [
{ name: 'Unsubscribe', href: '{{unsubscribe_url}}' },
{ name: 'View in Browser', href: '{{webview_url}}' },
],
},
{
name: 'Social',
specialLinks: [
{ name: 'Share on Twitter', href: '{{share_twitter_url}}' },
{ name: 'Share on Facebook', href: '{{share_facebook_url}}' },
],
},
],
}
}
Runtime
dragble.setSpecialLinks({
customSpecialLinks: [
{ name: 'Survey', href: 'https://example.com/survey' },
],
});
const links = await dragble.getSpecialLinks();
Fonts
FontsConfig
interface FontsConfig {
excludeDefaults?: boolean; // Hide built-in fonts, show only custom (default: false)
customFonts?: FontDefinition[];
}
interface FontDefinition {
label: string; // Display label in dropdown
value: string; // CSS font-family value
url?: string; // URL to load font (Google Fonts, etc.)
weights?: number[]; // Available font weights (e.g., [400, 700])
defaultFont?: boolean; // Whether this is a default system font
}
Example
options: {
fonts: {
excludeDefaults: false,
customFonts: [
{
label: 'Inter',
value: "'Inter', sans-serif",
url: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap',
weights: [400, 500, 600, 700],
},
{
label: 'Playfair Display',
value: "'Playfair Display', serif",
url: 'https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&display=swap',
weights: [400, 700],
},
],
}
}
Runtime
dragble.setFonts({
customFonts: [
{ label: 'Roboto', value: "'Roboto', sans-serif", url: 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap' },
],
});
const fonts = await dragble.getFonts();
Display Conditions
Display conditions enable conditional rendering of rows based on user data or context. Conditions wrap row HTML with before/after syntax (e.g., Liquid, Jinja, Handlebars) that the sending platform evaluates at render time.
DisplayConditionsConfig
interface DisplayConditionsConfig {
enabled?: boolean; // Enable feature (default: false)
conditions?: DisplayConditionDefinition[]; // Pre-defined conditions for picker
permissions?: DisplayConditionsPermissions;
}
interface DisplayConditionDefinition {
type: string; // Category (e.g., 'Customer Segment')
label: string; // Display label in picker
description?: string;
before: string; // Syntax before the row (e.g., '{% if customer.vip %}')
after: string; // Syntax after the row (e.g., '{% endif %}')
}
interface DisplayConditionsPermissions {
canSelect?: boolean; // Select from pre-defined conditions (default: true)
canAdd?: boolean; // Add custom conditions with own syntax (default: true)
canEdit?: boolean; // Edit existing conditions (default: true)
canRemove?: boolean; // Remove conditions from rows (default: true)
}
Template Engine Syntax
The before and after fields wrap the row's HTML at export time:
<!-- before -->
{% if customer.tier == "VIP" %}
<tr><!-- row HTML --></tr>
{% endif %}
<!-- after -->
Any template engine syntax works (Liquid, Jinja2, Handlebars, Mustache, etc.) since the editor passes these strings through verbatim.
Example
options: {
displayConditions: {
enabled: true,
conditions: [
{
type: 'Customer Segment',
label: 'VIP Members',
description: 'Only show to VIP tier customers',
before: '{% if customer.tier == "VIP" %}',
after: '{% endif %}',
},
{
type: 'Cart Status',
label: 'Has Items in Cart',
before: '{% if cart.items_count > 0 %}',
after: '{% endif %}',
},
{
type: 'Location',
label: 'US Customers Only',
before: '{{#if (eq country "US")}}',
after: '{{/if}}',
},
],
permissions: {
canSelect: true,
canAdd: false, // Users can only pick from pre-defined, not create custom
canEdit: false,
canRemove: true,
},
}
}
Runtime
dragble.setDisplayConditions({
enabled: true,
conditions: [
{ type: 'Segment', label: 'New Users', before: '{% if user.new %}', after: '{% endif %}' },
],
permissions: { canSelect: true, canAdd: true, canRemove: true },
});
// Disable display conditions
dragble.setDisplayConditions({ enabled: false });
Localization
Supported Locales
The editor ships with full translations for 29 locales (BCP 47 format):
| Code | Language |
|---|---|
en-US | English (US) |
en-CA | English (Canada) |
ar-AE | Arabic (UAE) — RTL |
zh-CN | Chinese (Simplified) |
zh-TW | Chinese (Traditional) |
cs-CZ | Czech |
da-DK | Danish |
nl-NL | Dutch |
et-EE | Estonian |
fa-IR | Farsi / Persian — RTL |
fi-FI | Finnish |
fr-FR | French (France) |
fr-CA | French (Canada) |
de-DE | German |
hu-HU | Hungarian |
id-ID | Indonesian |
it-IT | Italian |
ja-JP | Japanese |
ko-KR | Korean |
no-NO | Norwegian |
pl-PL | Polish |
pt-BR | Portuguese (Brazil) |
pt-PT | Portuguese (Portugal) |
ru-RU | Russian |
es-ES | Spanish |
sv-SE | Swedish |
tr-TR | Turkish |
uk-UA | Ukrainian |
vi-VN | Vietnamese |
Base codes (e.g., 'en', 'fr', 'de') are also accepted and auto-mapped to their default regional variant.
Configuration
options: {
locale: 'fr-FR',
// Override or extend built-in translations
translations: {
'fr-FR': {
'content_tools.paragraph': 'Mon Paragraphe',
'buttons.save': 'Sauvegarder',
},
// Add a completely new language
'th': {
'content_tools.paragraph': 'ย่อหน้า',
'buttons.save': 'บันทึก',
// Missing keys fall back to English
},
},
textDirection: 'ltr', // 'ltr' | 'rtl'. Auto-set when language has rtl flag.
// Template language (distinct from UI locale)
language: {
label: 'العربية',
value: 'ar-SA',
rtl: true, // Auto-detects RTL from language code (ar, he, fa, ur) when omitted
default: false,
},
}
Priority: translations[locale] > built-in locale > English US defaults.
Runtime
// Switch UI locale
dragble.setLocale('fr-FR');
// Switch with custom overrides
dragble.setLocale('fr-CA', { 'buttons.save': 'Sauvegarder' });
// Set template language (auto-switches text direction for RTL)
dragble.setLanguage({ label: 'العربية', value: 'ar-SA', rtl: true });
// Get current template language
const lang = await dragble.getLanguage();
// Manual text direction control
dragble.setTextDirection('rtl');
const dir = await dragble.getTextDirection();
Collaboration
Team collaboration enables commenting, reviewer roles, and @mentions on the editor canvas.
CollaborationFeaturesConfig
interface CollaborationFeaturesConfig {
enabled?: boolean; // Enable collaboration (default: false)
role?: 'editor' | 'reviewer'; // 'editor' = full edit + comment, 'reviewer' = read-only + comment
commenting?: boolean | CollaborationCommentingConfig;
onComment?: (action: CommentAction) => void;
}
interface CollaborationCommentingConfig {
enabled?: boolean; // Enable commenting (default: true when collaboration enabled)
mentions?: boolean; // Enable @mentions (default: true)
getMentions?: (search: string) => Promise<MentionUser[]>;
}
interface MentionUser {
userHandle: string; // e.g., '@jane'
username: string; // 'Jane Smith'
userColor?: string; // '#3498DB'
}
CommentAction Types
| Type | Description |
|---|---|
NEW_COMMENT | A new comment or reply was created |
COMMENT_EDITED | An existing comment's content was modified |
COMMENT_DELETED | A comment was removed |
COMMENT_THREAD_RESOLVED | A root comment thread was marked as resolved |
COMMENT_THREAD_REOPENED | A previously resolved thread was reopened |
Requirements
Collaboration requires user.id to be set in options so comments can be attributed:
options: {
user: { id: 'user-123', name: 'Jane Doe', email: '[email protected]', color: '#3b82f6' },
}
Simple Example
options: {
user: { id: 'user-123', name: 'Jane Doe' },
features: {
collaboration: true, // Enable commenting for current user as 'editor' role
},
}
Reviewer Role
options: {
user: { id: 'user-456', name: 'Bob Reviewer' },
features: {
collaboration: {
enabled: true,
role: 'reviewer', // Read-only editing + commenting
commenting: true,
},
},
}
Advanced with @Mentions and Notifications
options: {
user: { id: 'user-123', name: 'Jane Doe', color: '#E74C3C' },
features: {
collaboration: {
enabled: true,
role: 'editor',
commenting: {
enabled: true,
mentions: true,
getMentions: async (search) => {
const res = await fetch(`/api/team?q=${encodeURIComponent(search)}`);
return await res.json();
// Returns: [{ userHandle: '@bob', username: 'Bob Smith', userColor: '#3498DB' }]
},
},
onComment: (action) => {
console.log(`${action.type}: ${action.comment.content}`);
if (action.type === 'NEW_COMMENT' && action.mentions.length > 0) {
notifyMentionedUsers(action.mentions);
}
// Sync all comments to backend
saveCommentsToBackend(action.comments);
},
},
},
}
Editor Behavior
EditorBehaviorConfig
interface EditorBehaviorConfig {
minRows?: number; // Minimum rows in body (default: 0)
maxRows?: number | null; // Maximum rows (default: unlimited)
contentType?: 'module'; // 'module' = single-row module editor (locked to 1 row)
autoSelectOnDrop?: boolean; // Auto-select element when dropped (default: false)
confirmOnDelete?: boolean; // Show confirm dialog before deleting (default: false)
rows?: boolean; // Show Rows accordion in Modules tab (default: true)
title?: string; // Editor title (shown in header)
}
Example
options: {
editor: {
minRows: 1,
maxRows: 10,
autoSelectOnDrop: true,
confirmOnDelete: true,
rows: true,
title: 'Newsletter Editor',
},
}
Module Editor (Single-Row)
options: {
editor: {
contentType: 'module', // Locks editor to 1 row for reusable content editing
},
}
Runtime
dragble.setEditorConfig({
maxRows: 5,
autoSelectOnDrop: true,
confirmOnDelete: false,
});
const config = await dragble.getEditorConfig();
Body/Canvas Values
Control the email/page body defaults (background, content width, fonts, links, preheader).
setBodyValues / getBodyValues
interface SetBodyValuesOptions {
backgroundColor?: string;
contentWidth?: string; // e.g., '600px'
contentAlign?: 'left' | 'center';
backgroundImage?: Partial<BackgroundImage>;
fontFamily?: FontFamily; // { label: string, value: string, url?: string }
textColor?: string;
preheaderText?: string; // Email only
linkStyle?: Partial<LinkStyle>;
}
Example
// Set at init
options: {
bodyValues: {
backgroundColor: '#f5f5f5',
contentWidth: '600px',
contentAlign: 'center',
textColor: '#333333',
fontFamily: { label: 'Inter', value: "'Inter', sans-serif" },
preheaderText: 'Check out our latest deals...',
linkStyle: {
linkColor: '#6366f1',
linkHoverColor: '#4f46e5',
linkUnderline: true,
linkHoverUnderline: true,
},
},
}
// Set at runtime
dragble.setBodyValues({
backgroundColor: '#ffffff',
contentWidth: '700px',
});
// Get current values
const bodyValues = await dragble.getBodyValues();
Tools Configuration
Built-in Tools
14 built-in content tools:
| Tool Key | Description |
|---|---|
text | Text / paragraph (alias: paragraph) |
heading | Heading |
button | Button / CTA |
image | Image |
divider | Horizontal divider |
menu | Navigation menu |
html | Raw HTML |
social | Social media icons |
video | Video embed |
table | Table |
timer | Countdown timer |
form | Form (AMP only in email mode) |
spacer | Vertical spacer |
paragraph | Alias for text |
ToolConfig
interface ToolConfig {
enabled?: boolean;
position?: number; // Sort order in tools panel
properties?: Record<string, ToolPropertyConfig>;
}
interface ToolPropertyConfig {
value?: unknown; // Default value override
editable?: boolean; // Whether user can change this property
}
Example
options: {
tools: {
video: { enabled: false },
form: { enabled: false },
heading: {
position: 1,
properties: {
text: { value: 'Default Heading Text' },
fontSize: { value: '28px' },
color: { value: '#111827' },
},
},
button: {
properties: {
backgroundColor: { value: '#6366f1' },
borderRadius: { value: '8px', editable: true },
},
},
image: {
properties: {
alt: { value: '', editable: true },
},
},
}
}
Runtime
dragble.setToolsConfig({
video: { enabled: true },
social: { enabled: false },
});
Popup Config
Popup configuration is only relevant when editorMode is 'popup'.
PopupConfig
interface PopupConfig {
defaultWidth?: string; // Default popup width
defaultHeight?: string; // Default popup height
exportMode?: 'full' | 'partial'; // 'full' = complete HTML document, 'partial' = embeddable fragment
popupId?: string; // Custom popup ID for HTML element IDs
}
Example
dragble.init({
containerId: 'editor',
editorKey: 'ek_xxx',
editorMode: 'popup',
popup: {
defaultWidth: '500px',
defaultHeight: 'auto',
exportMode: 'full',
popupId: 'my-popup',
},
});
getPopupValues
Retrieve the current popup settings from the design:
const popupValues = await dragble.getPopupValues();
// Returns: {
// campaignType: 'lightbox',
// position: { horizontal: 'center', vertical: 'center' },
// width: '500px',
// height: 'auto',
// overlay: { enabled: true, color: 'rgba(0,0,0,0.5)', closeOnClick: true },
// closeButton: { enabled: true, position: 'top-right', size: '24px', color: '#fff', ... },
// animation: 'fade',
// animationDuration: '300ms',
// borderRadius: '12px',
// boxShadow: '0 25px 50px rgba(0,0,0,0.25)',
// padding: '20px',
// border: { width: '0', style: 'none', color: '#000' },
// displayDelay: 0,
// contentAlign: 'center',
// contentVerticalAlign: 'middle',
// }
Note: backgroundColor and backgroundImage are NOT part of popup values. They are managed through bodyValues, same as email/web mode.
Common Mistakes & Troubleshooting
1. Using accentColor with branded themes
// WRONG: accentColor is ignored with dragble-light / dragble-dark
appearance: { theme: 'dragble-light', accentColor: 'teal' }
// CORRECT: Use generic themes for custom accent
appearance: { theme: 'light', accentColor: 'teal' }
2. Missing user.id for collaboration
// WRONG: Collaboration won't attribute comments
features: { collaboration: true }
// CORRECT: Always set user.id
options: {
user: { id: 'user-123', name: 'Jane' },
features: { collaboration: true },
}
3. Calling methods before editor is ready
// WRONG: Editor may not be ready yet
dragble.init({ ... });
dragble.setMergeTags({ ... }); // May throw
// CORRECT: Use onReady callback
dragble.init({
containerId: 'editor',
editorKey: 'ek_xxx',
callbacks: {
onReady: () => {
dragble.setMergeTags({ customMergeTags: [...] });
},
},
});
4. Confusing locale (UI) with language (template content)
localecontrols the editor interface language (button labels, panel text, tooltips)languagecontrols the template content direction and language metadata
options: {
locale: 'en-US', // Editor UI in English
language: { label: 'العربية', value: 'ar-SA', rtl: true }, // Template content in Arabic (RTL)
}
5. Using panels instead of sidePanel
panels is deprecated. Use sidePanel for all panel configuration:
// WRONG (deprecated)
appearance: { panels: { tools: { dock: 'left' } } }
// CORRECT
appearance: { sidePanel: { dock: 'left', width: 380 } }
6. Expecting backgroundColor in popup values
Popup background color and image are managed through bodyValues, not popupValues:
// Access popup background via design, not popup values
const design = await dragble.getDesign();
const bgColor = design.body.values.backgroundColor;
7. Feature flags vs plan permissions
Feature flags can only disable features, not grant them. If a feature requires a plan upgrade (e.g., image editor, dynamic image), setting features.imageEditor: true won't work unless the plan allows it. Setting features.imageEditor: false always disables it regardless of plan.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.