Skip to content

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.


AttributeTypeDefaultPurpose
mm-editableflag-Makes an element’s content editable
mm-labelstringelement typeHuman-readable name for the field
mm-typetext | textarea | richtextInput type in the editor
mm-groupstringnoneGroups related fields together
mm-maxlengthnumberunlimitedCharacter limit for text fields
mm-presetsstringnoneAssigns style preset sets to an element
mm-idstringauto-generatedCustom identifier for editable elements

These attributes only apply when mm-type="rich" is set.

AttributeTypeDefaultPurpose
mm-rich-controlsstringbold,italic,underline,link,clearWhich formatting buttons to show
mm-link-colorhex color#3498DBDefault link color
mm-link-underlinetrue | falsetrueWhether links are underlined
mm-link-boldtrue | falsefalseWhether links are bold
mm-color-modepresets | bothbothColor picker mode
mm-color-presetsstringnonePredefined color options
ElementPurpose
<mm-presets>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

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).

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-id value 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-id on elements with mm-editable or mm-presets attributes.
  • Stripped from exports - Like all mm-* attributes, mm-id is 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-presets="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.


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.


Specifies which input field type appears in the editor. Defaults to text if omitted.

ValueDescription
textSingle-line text input (default)
textareaMulti-line text input for longer content
richRich 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.


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>

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.


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.

Rich text fields behave differently based on the parent element:

  • Block elements (<td>, <div>) allow multiple paragraphs - pressing Enter creates a new paragraph
  • Inline elements (<p>, <h1>, <span>, etc.) preserve single-line behavior - formatting is applied but paragraph structure is maintained
<!-- Block mode: allows multiple paragraphs -->
<td mm-editable mm-type="rich" mm-label="Body Content">
<p>First paragraph.</p>
<p>Second paragraph.</p>
</td>
<!-- Inline mode: single paragraph with formatting -->
<p mm-editable mm-type="rich" mm-label="Tagline">
Your brand <strong>tagline</strong> here.
</p>

Specifies which formatting buttons appear in the rich text toolbar. Provide a comma-separated list of control names.

Default: bold,italic,underline,link,clear

ControlDescription
boldBold text formatting
italicItalic text formatting
underlineUnderlined text
strikeStrikethrough text
linkInsert and edit hyperlinks
colorText color picker
clearRemove 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 simple fields -->
<p mm-editable mm-type="rich" mm-rich-controls="bold,italic" mm-label="Caption">
Only bold and italic available.
</p>
<!-- 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>

Control how links appear when inserted via the rich text editor.

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>

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>

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>

Control how the text color picker behaves in rich text fields. These only apply when color is included in mm-rich-controls.

Controls the color picker behavior.

ValueDescription
bothShows preset colors (if defined) plus a custom color picker (default)
presetsOnly 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>

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 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.

Style presets have two components:

  1. Preset set definitions (<mm-presets>) - Define the available choices and their CSS styles
  2. Preset assignments (mm-presets attribute) - 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.


Use <mm-presets> elements to define sets of style choices. Each contains <mm-choice> elements specifying the available styles.

LocationScopeUse case
Template headerGlobal - available to all modulesCommon presets: spacing, fonts, brand colors
Inside a moduleModule-specificPresets unique to that module’s design

Place <mm-presets> elements in the template header block, typically after the <body> tag:

<body style="margin: 0; padding: 0;">
<mm-presets 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-presets>
<mm-presets 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-presets>
<!-- 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-presets> definitions. This means any preset set defined in the header can be referenced by any module using the mm-presets attribute.

Place <mm-presets> at the beginning of a module’s HTML:

<mm-presets 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-presets>
<table role="presentation" width="100%">
<tr>
<td mm-presets="spacing,hero-layout" style="padding: 40px 20px; text-align: center;">
<h1 mm-editable mm-label="Headline">Welcome</h1>
</td>
</tr>
</table>

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-presets name="spacing" label="Section Spacing" default="standard">
<mm-choice name="compact" style="padding: 20px;" />
<mm-choice name="standard" style="padding: 40px;" />
</mm-presets>

And a module also defines:

<mm-presets name="spacing" label="Module Spacing" default="tight">
<mm-choice name="tight" style="padding: 10px;" />
<mm-choice name="normal" style="padding: 30px;" />
</mm-presets>

The module’s “spacing” definition completely replaces the global one for that module. Elements referencing mm-presets="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.


Defines a set of style choices.

AttributeRequiredDefaultDescription
nameYes-Unique identifier (used in mm-presets attribute)
labelNoAuto-generated from nameHuman-readable name shown in editor
defaultNoFirst choiceWhich choice is selected by default

If label is omitted, the name is automatically formatted (e.g., “bg-color” becomes “Bg Color”).


Defines a single choice within a preset set. This element is also used within interactive choice variables (see Variables section).

AttributeRequiredDescription
nameYesChoice identifier and display name
styleYesCSS styles to apply when selected (for presets only)
valueContext-dependentThe value substituted (for interactive variables only)
defaultNoFlag attribute marking the default choice

In preset sets:

<mm-presets 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-presets>

Use the mm-presets 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-presets="spacing" style="padding: 40px 20px;">
Content here
</td>
<!-- Multiple preset sets (comma-separated) -->
<td mm-presets="spacing,bg-color" style="padding: 40px 20px; background-color: #ffffff;">
Content here
</td>

How styles are applied:

  1. The element’s inline style attribute provides the base/default styles
  2. When a user selects a choice, those styles are merged with the base styles
  3. 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-presets="spacing,bg-color" style="padding: 40px 20px;">

For example, if both preset sets included a color property:

  • spacing choice sets color: #333333
  • bg-color choice sets color: #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-presets:

<td mm-editable mm-presets="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-presets="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.


When preset sets are assigned to elements, the campaign editor displays:

  1. Style dropdown menus in the sidebar for each preset set
  2. Real-time preview updates when selections change
  3. 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 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).

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 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 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 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 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:

AttributeRequiredDescription
valueYesThe value substituted into {{varName}}
nameNoDisplay name shown in the dropdown. Falls back to value if omitted.
defaultNoFlag attribute. Marks this choice as the default selection.

Interactive variables can be universal (campaign-wide) or element-scoped (resolved per editable element).

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.

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.


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.


Defines a single variable.

AttributeRequiredDescription
nameYesVariable identifier, used as {{name}} in HTML
valueNoIf present, makes this a static variable (constant substitution). If absent, makes it interactive.
typeNotext (default) or choice. Only for interactive variables.
labelNoHuman-readable name shown in editor. Auto-generated from name if omitted.
universalNoFlag attribute. If present, variable is campaign-wide rather than element-scoped.
defaultNoDefault value for text-type interactive variables.
hintNoHelp 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>

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 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).

Variants have three components:

  1. Variant set definition (<mm-variants>) - Defines the available choices and shared fields
  2. Field definitions (<mm-field>) - Specify editable fields used by all variant choices
  3. 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.


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>

Defines a set of swappable HTML variants.

AttributeRequiredDefaultDescription
nameYes-Unique identifier for the variant set
labelNoAuto-generated from nameHuman-readable name shown in editor
defaultNoFirst variantWhich variant choice is selected by default

Defines an editable field shared by all variants in the set. Fields appear in the campaign editor when editing the variant.

AttributeRequiredDefaultDescription
nameYes-Field identifier, used as {{name}} in variant templates
labelNoAuto-generated from nameHuman-readable name shown in editor
typeNotextInput type: text or url
maxlengthNoUnlimitedCharacter limit for the field
<mm-field name="headline" label="Headline" type="text" maxlength="50" />
<mm-field name="ctaUrl" label="CTA URL" type="url" />

Defines a single variant choice with its HTML template.

AttributeRequiredDescription
nameYesChoice 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>

<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

This example demonstrates editable fields, grouping, character limits, rich text, and style presets working together:

<!-- Module-specific preset set -->
<mm-presets 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-presets>
<!-- Module content -->
<table role="presentation" width="100%" mm-group="Hero Section">
<tr>
<td mm-presets="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 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">
<p>Rich text content with <strong>formatting</strong> and <a href="#">brand-colored links</a>.</p>
</td>
<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)

When campaigns are exported, Modular Mail produces clean HTML:

  1. Custom elements removed - <mm-presets>, <mm-choice>, <mm-variables>, <mm-variable>, <mm-variants>, <mm-variant>, and <mm-field> elements are stripped
  2. Attributes removed - All mm-* attributes are removed
  3. Styles applied - Selected preset styles are merged into element style attributes
  4. Variables processed - All {{variableName}} placeholders are replaced with their values
  5. Variants rendered - Variant blocks are replaced with the rendered HTML of the selected variant choice
  6. 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.