Full Tag Reference
This page documents all HTML attributes and custom elements used by Modular Mail to define editable content, style presets, variables, and variants in your email templates.
Quick reference
Section titled “Quick reference”Core attributes
Section titled “Core attributes”| Attribute | Type | Default | Purpose |
|---|---|---|---|
mm-editable | flag or lock flags | - | Makes an element’s content editable; accepts optional lock flags |
mm-label | string | element type | Human-readable name for the field |
mm-type | text | textarea | rich | text | Input type in the editor |
mm-group | string | none | Groups related fields together |
mm-maxlength | number | unlimited | Character limit for text fields |
mm-hint | string | none | Help text shown below the field in the editor sidebar |
mm-preset | string | none | Assigns style preset sets to an element |
mm-id | string | auto-generated | Custom identifier for editable elements |
mm-hide | space-separated tokens | - | Controls visibility: toggle, toggle:off, auto |
mm-show | "presetName:choiceName" | - | Show element only when a preset condition is met |
mm-repeat-master | string | - | Marks element as the master template for a repeater |
mm-repeat-label | string | humanized name | Human-readable label for the repeater |
mm-repeat-min | number | 1 | Minimum number of repeater instances |
mm-repeat-max | number | 10 | Maximum number of repeater instances |
Rich text attributes
Section titled “Rich text attributes”These attributes only apply when mm-type="rich" is set.
| Attribute | Type | Default | Purpose |
|---|---|---|---|
mm-rich-controls | string | bold,italic,underline,link,clear | Which formatting buttons to show |
mm-paragraph-spacing | CSS value | inherited | Space between paragraphs (e.g. 8px, 1em) |
mm-link-color | hex color | #3498DB | Default link color |
mm-link-underline | true | false | true | Whether links are underlined |
mm-link-bold | true | false | false | Whether links are bold |
mm-color-mode | presets | both | both | Color picker mode |
mm-color-presets | string | none | Predefined color options |
Custom elements
Section titled “Custom elements”| Element | Purpose |
|---|---|
<mm-preset> | Define a style preset set |
<mm-choice> | A single choice within a preset set or interactive variable |
<mm-variables> | Container for variable definitions |
<mm-variable> | Define a static or interactive variable |
<mm-variants> | Define a set of swappable HTML blocks with fields |
<mm-variant> | A single variant choice with template HTML |
<mm-field> | Define a field within a variant set |
<mm-repeat-instance> | A single instance of a repeater row |
Core attributes
Section titled “Core attributes”mm-editable
Section titled “mm-editable”Add this attribute to any element you want to make editable. Modular Mail automatically assigns a unique identifier (mm-id) to each editable element for tracking.
<p mm-editable>This text can be edited.</p>The editor automatically detects the element type and creates appropriate fields:
- Standard elements (
<p>,<h1>,<span>,<td>,<div>, etc.) create a text field for the inner content. - Links (
<a>) create two fields: one for the URL (href) and one for the link text. - Images (
<img>) create two fields: one for the source URL (src) and one for the alt text (alt).
Lock flags
Section titled “Lock flags”Pass space-separated lock flags as the attribute value to restrict which properties of an element can be edited. This is useful when you want to allow some changes but protect others — for example, locking an image’s src so editors can only update its alt text.
| Flag | Effect |
|---|---|
lock:content | Prevent editing the element’s text content |
lock:src | Prevent editing the src attribute (images) |
lock:alt | Prevent editing the alt attribute (images) |
lock:href | Prevent editing the href attribute (links) |
<!-- Allow editing alt text, but lock the image source --><img mm-editable="lock:src" mm-label="Hero Image" src="hero.jpg" alt="Spring collection">
<!-- Allow editing link text, but lock the URL --><a mm-editable="lock:href" mm-label="Terms Link" href="/legal/terms">Terms and Conditions</a>
<!-- Image where only alt text is editable --><img mm-editable="lock:src" mm-label="Logo" src="logo.png" alt="Company logo">
<!-- Multiple flags: lock both src and alt on an image where the image is fully controlled --><img mm-editable="lock:src lock:alt" mm-label="Fixed Promo Banner" src="promo.jpg" alt="Summer sale">Lock flags can be combined. An element can also have mm-editable alongside mm-preset — see the Style presets section.
Provides a custom identifier for editable elements. This attribute is optional—if omitted, Modular Mail automatically generates a unique ID for tracking purposes.
<!-- Auto-generated ID (default behavior) --><h1 mm-editable mm-label="Headline">Welcome</h1>
<!-- Custom ID provided by developer --><h1 mm-editable mm-label="Headline" mm-id="hero-headline">Welcome</h1>When to use custom IDs:
Custom IDs are useful when you need to reference specific fields consistently across template versions. For example, if you’re tracking which fields are most frequently edited or building integrations that target specific content areas, custom IDs ensure those references remain stable even as the template evolves.
Important considerations:
- Uniqueness required - Each
mm-idvalue must be unique within a template. Duplicate IDs trigger a validation warning. - Preserved values - When you provide an
mm-id, the system preserves your value instead of overwriting it with an auto-generated one. - Works with both attributes - You can use
mm-idon elements withmm-editableormm-presetattributes. - Stripped from exports - Like all
mm-*attributes,mm-idis removed from exported HTML.
<!-- Multiple elements with custom IDs --><table> <tr> <td> <h1 mm-editable mm-label="Hero Headline" mm-id="hero-h1">Welcome</h1> <p mm-editable mm-label="Hero Subheadline" mm-id="hero-subhead">Your message here</p> <a mm-editable mm-label="Primary CTA" mm-id="hero-cta" href="#">Learn More</a> </td> </tr></table>
<!-- Style presets with custom ID --><td mm-preset="spacing,bg-color" mm-id="hero-section" style="padding: 40px;"> Content here</td>Most templates don’t need custom IDs—the auto-generated values work well for typical use cases. Use mm-id only when you have a specific reason to control the identifier values.
mm-label
Section titled “mm-label”Provides a human-readable name for the field in the editor sidebar. If omitted, a default label is generated based on the element type (“Link” for links, “Image” for images, or the tag name with ID for other elements).
<h1 mm-editable mm-label="Hero Headline">Welcome</h1><a mm-editable mm-label="Primary CTA" href="#">Learn More</a><img mm-editable mm-label="Product Image" src="product.jpg" alt="Product">Always use clear, descriptive labels. Your team will see “Hero Headline” in the editor instead of a generic identifier.
mm-type
Section titled “mm-type”Specifies which input field type appears in the editor. Defaults to text if omitted.
| Value | Description |
|---|---|
text | Single-line text input (default) |
textarea | Multi-line text input for longer content |
rich | Rich text editor with formatting toolbar |
<!-- Single-line input (default) --><h1 mm-editable mm-label="Headline">Title</h1>
<!-- Multi-line input --><p mm-editable mm-label="Description" mm-type="textarea"> Longer content that might span multiple lines.</p>
<!-- Rich text with formatting --><td mm-editable mm-label="Body Content" mm-type="rich"> <p>Content with <strong>bold</strong> and <a href="#">links</a>.</p></td>Use textarea for paragraphs or content that spans multiple lines. Use rich when your team needs formatting options like bold, italic, links, or text colors.
mm-group
Section titled “mm-group”Groups related fields together under a collapsible section in the editor sidebar. Apply this to a parent element and all editable children automatically inherit the group.
<table mm-group="Hero Section"> <tr> <td> <h1 mm-editable mm-label="Headline">Welcome</h1> <p mm-editable mm-label="Subheadline">Your message here</p> <a mm-editable mm-label="CTA Button" href="#">Learn More</a> </td> </tr></table>All three fields appear under “Hero Section” in the editor, making it easier for your team to find related content.
You can also apply mm-group directly to an individual editable element:
<p mm-editable mm-label="Disclaimer" mm-group="Legal">Terms apply.</p>mm-maxlength
Section titled “mm-maxlength”Sets a character limit for text fields. The editor displays a character counter and prevents content from exceeding the limit. If omitted, no limit is enforced.
<p mm-editable mm-label="Preheader" mm-maxlength="100"> Preview text shown in inbox...</p>This is useful for:
- Preheader text - Most email clients display 40-130 characters
- Subject lines - Keep under 50 characters for mobile
- Headlines - Prevent layout-breaking long titles
- Button text - Keep CTAs concise
The character counter appears below the input field, showing current length and the maximum allowed.
mm-hint
Section titled “mm-hint”Displays help text below the field in the editor sidebar. Use it to give your team context about what a field is for, what format to use, or what constraints to keep in mind.
<p mm-editable mm-label="Preheader" mm-maxlength="100" mm-hint="Shown as preview text in most inboxes. Keep under 90 characters."> Your preheader text here</p>
<img mm-editable mm-label="Hero Image" mm-hint="Recommended size: 1200 × 600px. Use a JPG or PNG." src="hero.jpg" alt="Hero">
<a mm-editable mm-label="Primary CTA" mm-hint="Use action verbs: Shop Now, Learn More, Get Started." href="#">Shop Now</a>mm-hint works on any editable element and also on elements with mm-hide="toggle".
Rich text editing
Section titled “Rich text editing”When you set mm-type="rich", Modular Mail provides a formatting toolbar for that field. Rich text fields preserve HTML formatting like bold, italic, and links.
How rich text mode works
Section titled “How rich text mode works”Apply mm-type="rich" to container elements — <td> or <div> — that can hold multiple paragraphs. The rich text editor generates <p> tags for each paragraph, so the container needs to be a block element that can hold them.
Note: Do not apply
mm-type="rich"directly to<p>,<h1>,<h2>, or<h3>elements. The editor writes<p>tags as children, which would create invalid nested paragraph markup. Use the parent<td>or<div>instead.
<!-- Correct: rich text on a container element --><td mm-editable mm-type="rich" mm-label="Body Content"> <p>First paragraph.</p> <p>Second paragraph.</p></td>
<!-- Correct: rich text on a div --><div mm-editable mm-type="rich" mm-label="Feature Description"> <p>Describe your feature here.</p></div>
<!-- Avoid: rich text on a <p> tag — the editor generates nested <p> tags --><!-- <p mm-editable mm-type="rich">...</p> -->mm-rich-controls
Section titled “mm-rich-controls”Specifies which formatting buttons appear in the rich text toolbar. Provide a comma-separated list of control names.
Default: bold,italic,underline,link,clear
| Control | Description |
|---|---|
bold | Bold text formatting |
italic | Italic text formatting |
underline | Underlined text |
strike | Strikethrough text |
link | Insert and edit hyperlinks |
color | Text color picker |
clear | Remove all formatting |
<!-- Default controls --><td mm-editable mm-type="rich" mm-label="Description"> <p>Uses default formatting: bold, italic, underline, link, clear.</p></td>
<!-- Minimal controls for a simple caption --><td mm-editable mm-type="rich" mm-rich-controls="bold,italic" mm-label="Caption"> <p>Only bold and italic available.</p></td>
<!-- Full controls including color --><td mm-editable mm-type="rich" mm-rich-controls="bold,italic,underline,strike,link,color,clear" mm-label="Rich Body"> <p>All formatting options available.</p></td>Link styling attributes
Section titled “Link styling attributes”Control how links appear when inserted via the rich text editor.
mm-link-color
Section titled “mm-link-color”Sets the default color for links. If omitted, links default to #3498DB (blue).
<td mm-editable mm-type="rich" mm-link-color="#1F7F4C"> <p>Links will be <a href="#">green</a> by default.</p></td>mm-link-underline
Section titled “mm-link-underline”Controls whether links are underlined. Defaults to true.
<td mm-editable mm-type="rich" mm-link-underline="false"> <p>Links will not have underlines.</p></td>mm-link-bold
Section titled “mm-link-bold”Controls whether links are bold. Defaults to false.
<td mm-editable mm-type="rich" mm-link-bold="true"> <p>Links will be <a href="#">bold</a>.</p></td>Combining link styles:
<td mm-editable mm-type="rich" mm-link-color="#E74C3C" mm-link-underline="false" mm-link-bold="true" mm-label="Promo Content"> <p>Links appear as bold red text without underlines.</p></td>mm-paragraph-spacing
Section titled “mm-paragraph-spacing”Controls the bottom margin between paragraphs in a rich text field. Set a value with a CSS unit (px, em, rem). Use 0 to remove all spacing between paragraphs.
This attribute is typically set through the Field Settings panel in the template editor, but you can also write it directly in your module code.
<!-- 8px spacing between paragraphs --><td mm-editable mm-type="rich" mm-label="Body Content" mm-paragraph-spacing="8px"> <p>First paragraph.</p> <p>Second paragraph.</p></td>
<!-- Tight spacing using em units --><td mm-editable mm-type="rich" mm-label="Compact Body" mm-paragraph-spacing="0.5em"> <p>Tight paragraph spacing.</p></td>If omitted, paragraph spacing uses the element’s inherited CSS margin.
Text color attributes
Section titled “Text color attributes”Control how the text color picker behaves in rich text fields. These only apply when color is included in mm-rich-controls.
mm-color-mode
Section titled “mm-color-mode”Controls the color picker behavior.
| Value | Description |
|---|---|
both | Shows preset colors (if defined) plus a custom color picker (default) |
presets | Only shows predefined colors from mm-color-presets |
<!-- Both presets and custom picker (default) --><td mm-editable mm-type="rich" mm-rich-controls="bold,italic,color" mm-color-presets="Brand:#1F7F4C,Accent:#E74C3C"> <p>Users see preset colors and can pick custom colors.</p></td>
<!-- Presets only - no custom picker --><td mm-editable mm-type="rich" mm-rich-controls="bold,italic,color" mm-color-mode="presets" mm-color-presets="Brand:#1F7F4C,Accent:#E74C3C,Dark:#333333"> <p>Users can only choose from preset colors.</p></td>mm-color-presets
Section titled “mm-color-presets”Defines preset colors for the text color picker. Format: Name:#hex,Name:#hex (name followed by colon and hex color).
<td mm-editable mm-type="rich" mm-rich-controls="bold,italic,color" mm-color-presets="Primary:#1F7F4C,Secondary:#1B69DE,Alert:#E74C3C,Dark:#333333"> <p>Quick access to brand colors.</p></td>Preset names appear as tooltips when hovering over color swatches in the editor.
Style presets
Section titled “Style presets”Style presets let campaign editors choose from predefined visual styles without editing code. This is ideal for offering variations like spacing, background colors, or alignment while maintaining brand consistency.
How style presets work
Section titled “How style presets work”Style presets have two components:
- Preset set definitions (
<mm-preset>) - Define the available choices and their CSS styles - Preset assignments (
mm-presetattribute) - Apply preset sets to specific elements
When a user selects a choice in the campaign editor, the CSS styles from that choice are applied to the element.
Renamed from
mm-presets— both the element and the attribute were previously namedmm-presets(plural). Templates authored before the rename need to be updated to the singular form; the plural is no longer recognized.
Defining preset sets
Section titled “Defining preset sets”Use <mm-preset> elements to define sets of style choices. Each contains <mm-choice> elements specifying the available styles.
Where to place preset set definitions
Section titled “Where to place preset set definitions”| Location | Scope | Use case |
|---|---|---|
| Template header | Global - available to all modules | Common presets: spacing, fonts, brand colors |
| Inside a module | Module-specific | Presets unique to that module’s design |
Global preset sets (in template header)
Section titled “Global preset sets (in template header)”Place <mm-preset> elements in the template header block, typically after the <body> tag:
<body style="margin: 0; padding: 0;">
<mm-preset name="spacing" label="Section Spacing" default="standard"> <mm-choice name="none" style="padding: 0;" /> <mm-choice name="compact" style="padding: 20px;" /> <mm-choice name="standard" style="padding: 40px 20px;" /> <mm-choice name="spacious" style="padding: 60px 20px;" /> </mm-preset>
<mm-preset name="bg-color" label="Background Color" default="white"> <mm-choice name="white" style="background-color: #ffffff;" /> <mm-choice name="light" style="background-color: #f5f5f5;" /> <mm-choice name="brand" style="background-color: #1F7F4C; color: #ffffff;" /> </mm-preset>
<!-- Rest of header content --></body>Global preset sets are available to all modules in the template. At render time, Modular Mail combines the header, all modules, and footer into a single document, then extracts all <mm-preset> definitions. This means any preset set defined in the header can be referenced by any module using the mm-preset attribute.
Module-specific preset sets
Section titled “Module-specific preset sets”Place <mm-preset> at the beginning of a module’s HTML:
<mm-preset name="hero-layout" label="Hero Layout" default="centered"> <mm-choice name="centered" style="text-align: center;" /> <mm-choice name="left" style="text-align: left;" /></mm-preset>
<table role="presentation" width="100%"> <tr> <td mm-preset="spacing,hero-layout" style="padding: 40px 20px; text-align: center;"> <h1 mm-editable mm-label="Headline">Welcome</h1> </td> </tr></table>Name collisions and precedence
Section titled “Name collisions and precedence”If a module defines a preset set with the same name as a global one, the module-specific definition takes precedence. This happens because the header HTML appears first in the combined document, and later definitions override earlier ones.
For example, if the header defines:
<mm-preset name="spacing" label="Section Spacing" default="standard"> <mm-choice name="compact" style="padding: 20px;" /> <mm-choice name="standard" style="padding: 40px;" /></mm-preset>And a module also defines:
<mm-preset name="spacing" label="Module Spacing" default="tight"> <mm-choice name="tight" style="padding: 10px;" /> <mm-choice name="normal" style="padding: 30px;" /></mm-preset>The module’s “spacing” definition completely replaces the global one for that module. Elements referencing mm-preset="spacing" within that module will see “tight” and “normal” choices, not “compact” and “standard”.
This override behavior is useful when a specific module needs different spacing presets than the rest of the template, but in most cases you should use unique names to avoid confusion.
<mm-preset> element
Section titled “<mm-preset> element”Defines a set of style choices.
| Attribute | Required | Default | Description |
|---|---|---|---|
name | Yes | - | Unique identifier (used in mm-preset attribute) |
label | No | Auto-generated from name | Human-readable name shown in editor |
default | No | First choice | Which choice is selected by default |
If label is omitted, the name is automatically formatted (e.g., “bg-color” becomes “Bg Color”).
<mm-choice> element
Section titled “<mm-choice> element”Defines a single choice within a preset set. This element is also used within interactive choice variables (see Variables section).
| Attribute | Required | Description |
|---|---|---|
name | Yes | Choice identifier and display name |
style | Yes | CSS styles to apply when selected (for presets only) |
value | Context-dependent | The value substituted (for interactive variables only) |
default | No | Flag attribute marking the default choice |
In preset sets:
<mm-preset name="button-color" label="Button Color" default="primary"> <mm-choice name="primary" style="background-color: #1F7F4C; color: #ffffff;" /> <mm-choice name="secondary" style="background-color: #3498DB; color: #ffffff;" /> <mm-choice name="dark" style="background-color: #333333; color: #ffffff;" /></mm-preset>Assigning presets to elements
Section titled “Assigning presets to elements”Use the mm-preset attribute to assign one or more preset sets to an element. The value references the name of defined preset sets.
<!-- Single preset set --><td mm-preset="spacing" style="padding: 40px 20px;"> Content here</td>
<!-- Multiple preset sets (comma-separated) --><td mm-preset="spacing,bg-color" style="padding: 40px 20px; background-color: #ffffff;"> Content here</td>How styles are applied:
- The element’s inline
styleattribute provides the base/default styles - When a user selects a choice, those styles are merged with the base styles
- Choice styles override base styles for the same CSS properties
Multiple preset sets and style precedence:
When you assign multiple preset sets to an element (comma-separated), they are applied in order from left to right. If two preset sets have choices that affect the same CSS property, the later preset set wins.
<!-- bg-color styles override any conflicting styles from spacing --><td mm-preset="spacing,bg-color" style="padding: 40px 20px;">For example, if both preset sets included a color property:
spacingchoice setscolor: #333333bg-colorchoice setscolor: #ffffff
The element would use color: #ffffff because bg-color comes after spacing in the list.
To avoid unexpected behavior, design your preset sets to control distinct CSS properties (one for spacing, another for colors, another for alignment, etc.).
Combining with editable content:
Elements can have both mm-editable and mm-preset:
<td mm-editable mm-preset="spacing,bg-color" mm-label="Hero Content" style="padding: 40px 20px;"> <p>This section is editable AND has style presets.</p></td>In the editor, this creates:
- Text field for the content (labeled “Hero Content”)
- Dropdown for “Section Spacing” choices
- Dropdown for “Background Color” choices
Non-editable elements with presets:
Elements can have style presets without being editable:
<table mm-preset="spacing" style="padding: 40px 20px;"> <tr> <td> <p mm-editable mm-label="Content">Text here</p> </td> </tr></table>The table has style presets but no editable content - users can change the spacing without modifying the structure.
Style presets in the editor
Section titled “Style presets in the editor”When preset sets are assigned to elements, the campaign editor displays:
- Style dropdown menus in the sidebar for each preset set
- Real-time preview updates when selections change
- Grouped display if the element is within an
mm-group
Preset sets defined in the module appear in the “Style Presets” section when editing that module.
Variables
Section titled “Variables”Variables provide dynamic placeholder substitution in your email templates. Modular Mail supports two types of variables: static variables (simple find-and-replace) and interactive variables (editable fields in the campaign editor).
How variables work
Section titled “How variables work”Variables are defined using <mm-variables> containers with <mm-variable> elements. Once defined, you reference them in your HTML using double-curly-brace syntax: {{variableName}}.
Variables can appear anywhere in your HTML content and in key attributes like src, href, style, background, bgcolor, alt, title, and class.
Important: Any {{placeholder}} that doesn’t match a defined variable is left unchanged. This allows ESP merge tags like {{first_name}} or {{company}} to pass through to your email service provider without interference.
Static variables
Section titled “Static variables”Static variables are simple constants defined by the template author. They have both a name and a value attribute. Every occurrence of {{variableName}} in the HTML gets replaced with the value at export time.
Use cases:
- Image CDN prefixes and transformations
- Brand colors and fonts
- API endpoints or tracking parameters
- Repeated URLs or text snippets
<mm-variables> <mm-variable name="cloudinaryPrefix" value="https://res.cloudinary.com/demo/image/upload/ar_1:1,c_fill,w_1500" /> <mm-variable name="brandColor" value="#1F7F4C" /> <mm-variable name="trackingParam" value="?utm_source=newsletter&utm_medium=email" /></mm-variables>
<!-- Usage in HTML --><img src="{{cloudinaryPrefix}}/sample.jpg" alt="Product" style="width: 100%;"><a href="https://example.com{{trackingParam}}" style="color: {{brandColor}};">Learn More</a>At export, this becomes:
<img src="https://res.cloudinary.com/demo/image/upload/ar_1:1,c_fill,w_1500/sample.jpg" alt="Product" style="width: 100%;"><a href="https://example.com?utm_source=newsletter&utm_medium=email" style="color: #1F7F4C;">Learn More</a>Static variables are processed at export time and do not appear in the campaign editor.
Interactive variables
Section titled “Interactive variables”Interactive variables create editable fields in the campaign editor. They are defined WITHOUT a value attribute and support two types: text inputs and dropdown choices.
Text variables
Section titled “Text variables”Text variables create a simple text input field. Users enter a value that gets substituted throughout the campaign.
<mm-variables> <mm-variable name="altSuffix" type="text" label="Alt Text Suffix" hint="Appended to all alt text" /> <mm-variable name="promoCode" type="text" label="Promo Code" default="WELCOME10" /></mm-variables>
<!-- Usage --><img src="product.jpg" alt="Product image {{altSuffix}}"><p>Use code {{promoCode}} at checkout</p>Choice variables
Section titled “Choice variables”Choice variables create a dropdown menu with predefined options using <mm-choice> child elements.
<mm-variables> <mm-variable name="imgGravity" type="choice" label="Image Gravity"> <mm-choice value="g_auto" name="Auto"></mm-choice> <mm-choice value="g_face" name="Face" default></mm-choice> <mm-choice value="g_center" name="Center"></mm-choice> </mm-variable></mm-variables>
<!-- Usage --><img src="https://res.cloudinary.com/demo/image/upload/{{imgGravity}}/sample.jpg" alt="Photo">The <mm-choice> element for interactive variables uses these attributes:
| Attribute | Required | Description |
|---|---|---|
value | Yes | The value substituted into {{varName}} |
name | No | Display name shown in the dropdown. Falls back to value if omitted. |
default | No | Flag attribute. Marks this choice as the default selection. |
Universal vs element-scoped variables
Section titled “Universal vs element-scoped variables”Interactive variables can be universal (campaign-wide) or element-scoped (resolved per editable element).
Universal variables
Section titled “Universal variables”Add the universal flag attribute to make a variable campaign-wide. The user sets it once and the value applies everywhere the variable appears.
<mm-variables> <mm-variable name="season" type="choice" label="Season Theme" universal> <mm-choice value="spring" name="Spring" default></mm-choice> <mm-choice value="summer" name="Summer"></mm-choice> <mm-choice value="fall" name="Fall"></mm-choice> <mm-choice value="winter" name="Winter"></mm-choice> </mm-variable></mm-variables>
<!-- Used in multiple modules --><img src="/images/hero-{{season}}.jpg" alt="{{season}} collection"><p>Shop our {{season}} collection</p>Universal variables appear once at the top of the campaign editor, not in individual element settings.
Element-scoped variables
Section titled “Element-scoped variables”Without the universal flag, variables are resolved per element. Each editable element with mm-id gets its own variable values.
<mm-variables> <mm-variable name="imgEffect" type="choice" label="Image Effect"> <mm-choice value="e_grayscale" name="Grayscale"></mm-choice> <mm-choice value="e_sepia" name="Sepia"></mm-choice> <mm-choice value="" name="None" default></mm-choice> </mm-variable></mm-variables>
<!-- Different elements can have different values --><img mm-id="hero-img" src="https://cdn.example.com/{{imgEffect}}/hero.jpg" alt="Hero"><img mm-id="product-img" src="https://cdn.example.com/{{imgEffect}}/product.jpg" alt="Product">The editor shows “Image Effect” settings separately for hero-img and product-img, allowing different choices for each.
<mm-variables> element
Section titled “<mm-variables> element”Container for variable definitions. Place this in the template header (for global variables) or at the beginning of a module (for module-specific variables).
<mm-variables> <!-- Variable definitions here --></mm-variables>No attributes required.
<mm-variable> element
Section titled “<mm-variable> element”Defines a single variable.
| Attribute | Required | Description |
|---|---|---|
name | Yes | Variable identifier, used as {{name}} in HTML |
value | No | If present, makes this a static variable (constant substitution). If absent, makes it interactive. |
type | No | text (default) or choice. Only for interactive variables. |
label | No | Human-readable name shown in editor. Auto-generated from name if omitted. |
universal | No | Flag attribute. If present, variable is campaign-wide rather than element-scoped. |
default | No | Default value for text-type interactive variables. |
hint | No | Help text shown below the field in the editor. |
Static variable example:
<mm-variable name="cdnUrl" value="https://cdn.example.com/v2" />Interactive text variable example:
<mm-variable name="eventDate" type="text" label="Event Date" default="March 15, 2026" hint="Format: Month Day, Year" />Interactive choice variable example:
<mm-variable name="buttonStyle" type="choice" label="Button Style" universal> <mm-choice value="rounded" name="Rounded" default></mm-choice> <mm-choice value="square" name="Square"></mm-choice></mm-variable>Variables in the editor
Section titled “Variables in the editor”Interactive variables appear in the campaign editor:
- Universal variables display in a “Campaign Variables” section at the top of the editor, above module content
- Element-scoped variables appear within each editable element’s settings panel
- Static variables are invisible to users and processed automatically at export
Variants
Section titled “Variants”Variants let template authors define swappable HTML blocks with editable fields. Think of them as “component variants”—for example, a button that can be “Primary” (solid fill) or “Secondary” (outline), where the campaign editor selects the style AND fills in the content (button text, URL).
How variants work
Section titled “How variants work”Variants have three components:
- Variant set definition (
<mm-variants>) - Defines the available choices and shared fields - Field definitions (
<mm-field>) - Specify editable fields used by all variant choices - Variant templates (
<mm-variant>) - HTML templates for each choice, with{{fieldName}}placeholders
When a user selects a variant choice and fills in the fields, Modular Mail renders that variant’s HTML template with the field values substituted. At export, the entire <mm-variants> block is replaced with the rendered HTML.
Defining variant sets
Section titled “Defining variant sets”Place <mm-variants> elements in your module HTML where you want the rendered variant to appear.
<mm-variants name="button-style" label="Button Style" default="Primary"> <!-- Shared fields used by all variants --> <mm-field name="text" label="Button Text" type="text" maxlength="30" /> <mm-field name="url" label="Button URL" type="url" />
<!-- Variant templates --> <mm-variant name="Primary"> <a href="{{url}}" style="display: inline-block; background: #1F7F4C; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px;"> {{text}} </a> </mm-variant>
<mm-variant name="Secondary"> <a href="{{url}}" style="display: inline-block; border: 2px solid #1F7F4C; color: #1F7F4C; padding: 10px 22px; text-decoration: none; border-radius: 4px;"> {{text}} </a> </mm-variant>
<mm-variant name="Text Link"> <a href="{{url}}" style="color: #1F7F4C; text-decoration: underline;"> {{text}} </a> </mm-variant></mm-variants>In the campaign editor, users see:
- A “Button Style” dropdown with choices: Primary, Secondary, Text Link
- Fields for “Button Text” and “Button URL”
When the user selects “Secondary” and enters text=“Shop Now” and url=“https://example.com/shop”, the system renders:
<a href="https://example.com/shop" style="display: inline-block; border: 2px solid #1F7F4C; color: #1F7F4C; padding: 10px 22px; text-decoration: none; border-radius: 4px;"> Shop Now</a><mm-variants> element
Section titled “<mm-variants> element”Defines a set of swappable HTML variants.
| Attribute | Required | Default | Description |
|---|---|---|---|
name | Yes | - | Unique identifier for the variant set |
label | No | Auto-generated from name | Human-readable name shown in editor |
default | No | First variant | Which variant choice is selected by default |
<mm-field> element
Section titled “<mm-field> element”Defines an editable field shared by all variants in the set. Fields appear in the campaign editor when editing the variant.
| Attribute | Required | Default | Description |
|---|---|---|---|
name | Yes | - | Field identifier, used as {{name}} in variant templates |
label | No | Auto-generated from name | Human-readable name shown in editor |
type | No | text | Input type: text or url |
maxlength | No | Unlimited | Character limit for the field |
<mm-field name="headline" label="Headline" type="text" maxlength="50" /><mm-field name="ctaUrl" label="CTA URL" type="url" /><mm-variant> element
Section titled “<mm-variant> element”Defines a single variant choice with its HTML template.
| Attribute | Required | Description |
|---|---|---|
name | Yes | Choice name shown in the variant dropdown |
The inner HTML of <mm-variant> is the template for that choice. Use {{fieldName}} placeholders that correspond to <mm-field> names defined in the parent <mm-variants>.
<mm-variant name="Centered Card"> <table width="100%" style="background: #f9f9f9; padding: 20px;"> <tr> <td style="text-align: center;"> <h2>{{headline}}</h2> <p>{{description}}</p> <a href="{{ctaUrl}}" style="background: #1F7F4C; color: white; padding: 12px 24px; text-decoration: none;"> {{ctaText}} </a> </td> </tr> </table></mm-variant>Complete variant example
Section titled “Complete variant example”<mm-variants name="cta-block" label="Call to Action Style" default="Button"> <mm-field name="heading" label="Heading" type="text" maxlength="60" /> <mm-field name="description" label="Description" type="text" maxlength="150" /> <mm-field name="linkText" label="Link Text" type="text" maxlength="30" /> <mm-field name="linkUrl" label="Link URL" type="url" />
<mm-variant name="Button"> <table width="100%" style="padding: 20px;"> <tr> <td style="text-align: center;"> <h2 style="margin: 0 0 10px; font-size: 24px;">{{heading}}</h2> <p style="margin: 0 0 20px; color: #666;">{{description}}</p> <a href="{{linkUrl}}" style="display: inline-block; background: #1F7F4C; color: white; padding: 14px 28px; text-decoration: none; border-radius: 4px;"> {{linkText}} </a> </td> </tr> </table> </mm-variant>
<mm-variant name="Text Link"> <table width="100%" style="padding: 20px;"> <tr> <td> <h2 style="margin: 0 0 10px; font-size: 24px;">{{heading}}</h2> <p style="margin: 0 0 10px; color: #666;">{{description}}</p> <a href="{{linkUrl}}" style="color: #1F7F4C; text-decoration: underline; font-weight: bold;"> {{linkText}} → </a> </td> </tr> </table> </mm-variant>
<mm-variant name="Banner"> <table width="100%" style="background: linear-gradient(135deg, #1F7F4C 0%, #166339 100%); padding: 30px;"> <tr> <td style="text-align: center;"> <h2 style="margin: 0 0 10px; font-size: 28px; color: white;">{{heading}}</h2> <p style="margin: 0 0 20px; color: rgba(255,255,255,0.9); font-size: 16px;">{{description}}</p> <a href="{{linkUrl}}" style="display: inline-block; background: white; color: #1F7F4C; padding: 14px 28px; text-decoration: none; border-radius: 4px; font-weight: bold;"> {{linkText}} </a> </td> </tr> </table> </mm-variant></mm-variants>In the editor, users see:
- Dropdown: “Call to Action Style” with options: Button, Text Link, Banner
- Fields: Heading, Description, Link Text, Link URL
- Live preview updates as they change the variant choice or field values
Visibility controls
Section titled “Visibility controls”mm-hide
Section titled “mm-hide”Controls whether an element appears in the exported email. Apply to any element — typically a row, section, or container — to give campaign editors a visibility toggle, or to automatically remove empty sections.
The value is a space-separated list of one or more tokens:
| Token | Behaviour |
|---|---|
toggle | Adds a show/hide toggle for this element in the editor sidebar. Visible by default. |
toggle:off | Same as toggle, but hidden by default. Editors must explicitly turn it on. |
auto | Automatically removes the element from the exported email when all of its editable descendants are empty (no text, no href, no src). |
Tokens can be combined. When both toggle and auto are present, an explicit editor toggle decision takes precedence over the auto-hide check.
Use mm-label to give the toggle a clear name, and mm-hint to explain when it should be used.
<!-- A section editors can show or hide --><tr mm-hide="toggle" mm-id="promo-row" mm-label="Promo Banner" mm-hint="Show during promotional periods only."> <td> <p mm-editable mm-label="Promo Text">Save 20% this weekend only.</p> </td></tr>
<!-- A section that is off by default --><tr mm-hide="toggle:off" mm-id="legal-row" mm-label="Legal Disclaimer"> <td> <p mm-editable mm-label="Disclaimer Text">Terms and conditions apply.</p> </td></tr>
<!-- Auto-removed when all fields inside are empty --><tr mm-hide="auto" mm-id="event-row"> <td> <p mm-editable mm-label="Event Name">Upcoming event</p> <a mm-editable mm-label="Event Link" href="#">Register</a> </td></tr>
<!-- Toggle + auto: editor can override, but auto-hides when empty if never touched --><tr mm-hide="toggle auto" mm-id="sponsor-row" mm-label="Sponsor Section"> <td> <img mm-editable mm-label="Sponsor Logo" src="" alt=""> </td></tr>Note: Elements with
mm-hidemust have anmm-idattribute for toggle state to be tracked. Without anmm-id, thetoggletoken has no effect.
mm-show
Section titled “mm-show”Makes an element conditionally visible based on a preset selection. When the specified preset choice is not active, the element is removed from the exported email entirely.
Format: "presetName:choiceName" — space-free, colon-separated. Multiple conditions can be comma-separated; the element is shown if any condition is met (OR logic).
<!-- Show only when the "layout" preset is set to "two-col" --><td mm-show="layout:two-col" style="width: 50%;"> <img src="product-2.jpg" alt="Second product"></td>
<!-- Show when layout is "hero" OR when theme is "dark" --><td mm-show="layout:hero,theme:dark"> <p mm-editable mm-label="Hero Subtext">Supporting copy here.</p></td>A common pattern is pairing mm-show with a layout preset to swap between single-column and two-column variations:
<mm-preset name="layout" label="Layout" default="single"> <mm-choice name="single" style="" /> <mm-choice name="two-col" style="" /></mm-preset>
<!-- Always shown --><td mm-show="layout:single,layout:two-col"> <img mm-editable mm-label="Primary Image" src="product.jpg" alt="Product"></td>
<!-- Only shown in two-column layout --><td mm-show="layout:two-col"> <img mm-editable mm-label="Secondary Image" src="product-2.jpg" alt="Second product"></td>Note: If the referenced preset or choice name does not exist, the element is treated as not visible and is removed from the export. Double-check your preset names are spelled consistently.
Repeaters
Section titled “Repeaters”Repeaters let campaign editors add, remove, and reorder instances of a content row or block. They are ideal for product grids, list items, team members, event listings, or any module where the number of items varies.
mm-repeat-master
Section titled “mm-repeat-master”Marks an element as the master template for a repeater. The master defines the structure and editable fields for each instance. Campaign editors create additional instances by cloning the master’s layout.
Each editable or preset-carrying descendant inside the master must carry an mm-ref attribute — a short identifier used to link the master field definition to per-instance values.
| Attribute | Required | Default | Description |
|---|---|---|---|
mm-repeat-master | Yes | - | Name identifier for the repeater |
mm-repeat-label | No | Humanized name | Label shown in the editor |
mm-repeat-min | No | 1 | Minimum number of instances |
mm-repeat-max | No | 10 | Maximum number of instances |
mm-label | No | - | Falls back to mm-repeat-label if that is not set |
<table role="presentation" width="100%"> <tbody> <!-- Master row: defines the repeater structure --> <tr mm-repeat-master="products" mm-repeat-label="Products" mm-repeat-min="1" mm-repeat-max="6" mm-id="products-master"> <td style="padding: 16px; width: 50%;"> <img mm-editable mm-label="Product Image" mm-ref="img" src="product.jpg" alt="Product" style="max-width: 100%;"> <p mm-editable mm-label="Product Name" mm-ref="name" mm-maxlength="60" style="font-weight: bold;">Product Name</p> <p mm-editable mm-label="Product Price" mm-ref="price" style="color: #666;">$0.00</p> <a mm-editable mm-label="Buy Link" mm-ref="cta" href="#" style="color: #1F7F4C;">Buy Now</a> </td> </tr> </tbody></table>In the campaign editor, users see the first instance (the master row) and a button to add more product rows. Each added row is independent — editors can set different image, name, price, and link for each.
mm-ref
Section titled “mm-ref”Every editable or preset-carrying element inside a mm-repeat-master must have an mm-ref attribute. This is a short identifier (like "title", "img", "cta") that links the field in the master definition to the corresponding value in each instance.
<h2 mm-editable mm-label="Headline" mm-ref="headline">Event Title</h2><img mm-editable mm-label="Image" mm-ref="img" src="event.jpg" alt="Event"><a mm-editable mm-label="Register Link" mm-ref="cta" href="#">Register Now</a>mm-ref values must be unique within a single repeater. Using the same mm-ref twice in one master results in a validation error.
Complete example
Section titled “Complete example”This example demonstrates editable fields, grouping, character limits, rich text, and style presets working together:
<!-- Module-specific preset set --><mm-preset name="hero-align" label="Content Alignment" default="center"> <mm-choice name="left" style="text-align: left;" /> <mm-choice name="center" style="text-align: center;" /></mm-preset>
<!-- Module content --><table role="presentation" width="100%" mm-group="Hero Section"> <tr> <td mm-preset="spacing,hero-align" style="padding: 40px 20px; text-align: center;">
<img mm-editable mm-label="Hero Image" src="hero.jpg" alt="Hero image" style="max-width: 100%;">
<h1 mm-editable mm-label="Headline" mm-maxlength="60" style="margin: 20px 0 10px; font-size: 32px;"> Welcome to Our Newsletter </h1>
<p mm-editable mm-label="Description" mm-type="textarea" mm-maxlength="150" style="color: #666666; margin: 0 0 20px; font-size: 16px;"> Stay informed with our latest updates, tips, and exclusive offers delivered straight to your inbox. </p>
</td> </tr> <tr> <td mm-editable mm-type="rich" mm-label="Body Content" mm-rich-controls="bold,italic,link,color" mm-link-color="#1F7F4C" mm-color-mode="presets" mm-color-presets="Brand:#1F7F4C,Accent:#E74C3C,Dark:#333" style="padding: 0 20px;"> <p>Rich text content with <strong>formatting</strong> and <a href="#">brand-colored links</a>.</p> </td> </tr> <tr> <td style="padding: 20px; text-align: center;"> <a mm-editable mm-label="CTA Button" href="#" style="display: inline-block; background: #1F7F4C; color: white; padding: 14px 28px; text-decoration: none; border-radius: 4px;"> Get Started </a> </td> </tr></table>This creates:
Style Presets:
- Section Spacing (from global template presets)
- Content Alignment (module-specific)
Editable Fields (grouped under “Hero Section”):
- Hero Image (source URL and alt text)
- Headline (single-line, 60 character limit)
- Description (multi-line, 150 character limit)
- Body Content (rich text with brand color presets)
- CTA Button (link URL and button text)
HTML output
Section titled “HTML output”When campaigns are exported, Modular Mail produces clean HTML:
- Custom elements removed —
<mm-preset>,<mm-choice>,<mm-variables>,<mm-variable>,<mm-variants>,<mm-variant>,<mm-field>, and<mm-repeat-instance>elements are stripped - Attributes removed — All
mm-*attributes are removed from the output - Styles applied — Selected preset styles are merged into element
styleattributes - Variables processed — All
{{variableName}}placeholders are replaced with their values - Variants rendered — Variant blocks are replaced with the rendered HTML of the selected variant choice
- Visibility resolved — Elements hidden via
mm-hideor whosemm-showconditions are not met are removed entirely - Repeaters expanded — Each repeater instance is rendered into real HTML rows; the master element and instance containers are removed
- Content preserved — User-entered content and formatting are maintained
The exported HTML is compatible with all major email service providers and preserves any ESP merge tags that don’t conflict with defined variable names.
Related resources
Section titled “Related resources”- Template Best Practices - Structuring editable regions effectively
- Quick Start Guide - Getting started with templates