Merge-Tags
Merge-Tags sind Tokens für dynamische Inhalte -- zum Beispiel den Namen eines Empfängers, einen Produktpreis oder eine Abmelde-URL. Sie erscheinen als hervorgehobene Tokens im Editor und werden unverändert im gerenderten MJML durchgereicht. Ihre E-Mail-Versandplattform ersetzt sie beim Versand durch echte Werte.
Templatical bietet integrierte Syntax-Presets für beliebte Plattformen und unterstützt benutzerdefinierte Syntaxdefinitionen.
Konfiguration
Übergeben Sie ein tags-Array, um Ihre Merge-Tags beim Editor zu registrieren. Wenn der Editor einen Merge-Tag-Wert im Inhalt erkennt (z. B. {{first_name}}), ersetzt er ihn visuell durch das menschenlesbare label ("First Name") — was das Template viel einfacher lesbar und bearbeitbar macht. Der Rohwert bleibt in der Ausgabe erhalten.

Beim Hovern über ein Tag wird der Rohwert hinter dem Label angezeigt.
Die Eigenschaft syntax ist optional und standardmäßig 'liquid'.
import { init } from '@templatical/editor';
const editor = await init({
container: '#editor',
mergeTags: {
tags: [
{ label: 'First Name', value: '{{first_name}}' },
{ label: 'Last Name', value: '{{last_name}}' },
{ label: 'Email', value: '{{email}}' },
{ label: 'Company', value: '{{company.name}}' },
{ label: 'Unsubscribe URL', value: '{{unsubscribe_url}}' },
],
},
});MergeTag-Typ
Jedes Tag wird mit einem Label (in der Editor-Oberfläche angezeigt) und einem Wert (der vollständige Merge-Tag-String einschließlich Trennzeichen) definiert. Zwei optionale Felder — group und description — werden vom integrierten Picker zur Gruppierung und Erklärung verwendet:
interface MergeTag {
label: string;
value: string;
group?: string; // optionale Gruppierung im Picker
description?: string; // optionaler Hilfetext im Picker
}Der value muss die Syntax-Trennzeichen enthalten. Zum Beispiel mit Liquid-Syntax:
value: '{{first_name}}'
Die Felder group und description sind ausschließlich für den Picker — sie erscheinen weder im Editor-Canvas, noch in der Autovervollständigung, noch in der gerenderten MJML-Ausgabe. Sie werden ignoriert, wenn Sie nur onRequest für die Tag-Auswahl verwenden.
Syntax-Presets
Templatical enthält vier integrierte Syntax-Presets. Die Einstellung syntax teilt dem Editor mit, wie sowohl Daten-Tags als auch Logik-Tags im Inhalt erkannt und hervorgehoben werden sollen.
Jedes Preset definiert zwei Muster:
- Daten-Tags -- Variable Merge-Tags wie der Name oder die E-Mail eines Empfängers
- Logik-Tags -- Kontrollflussanweisungen wie Bedingungen und Schleifen
| Preset | Daten-Tag | Logik-Tag | Plattform |
|---|---|---|---|
'liquid' | {{first_name}} | {% if vip %} | Shopify, Jekyll, Django, Jinja2 |
'handlebars' | {{first_name}} | {{#if vip}} | Handlebars.js, Mandrill |
'mailchimp' | *|FIRST_NAME|* | *|IF:VIP|* | Mailchimp |
'ampscript' | %%=first_name=%% | %%[IF @vip]%% | Salesforce Marketing Cloud |
mergeTags: {
syntax: 'handlebars',
tags: [
{ label: 'First Name', value: '{{first_name}}' },
],
}Logik-Tags
Neben Daten-Tags erkennt der Editor auch Logik-Tags -- bedingte Anweisungen, Schleifen und andere Kontrollflusssyntax, die von Ihrer E-Mail-Plattform verwendet wird. Diese werden automatisch mit dem logic-Regex-Muster aus dem ausgewählten Syntax-Preset erkannt.
Wenn ein Logik-Tag im Inhalt erkannt wird, extrahiert der Editor das Schlüsselwort (die erste Erfassungsgruppe aus der Logik-Regex) und zeigt es als Großbuchstaben-Abzeichen an -- zum Beispiel wird {% if customer.vip %} als IF gerendert und {% endif %} als ENDIF. Beim Hovern über das Abzeichen wird der vollständige Tag-Wert als Tooltip angezeigt. Benutzer können auf das Abzeichen klicken, um den Rohwert zu bearbeiten.

Logik-Tags werden anders formatiert als Daten-Tags (umrahmtes Abzeichen mit Primärfarbe vs. gefüllter Hintergrund), sodass Template-Autoren auf einen Blick zwischen Daten-Tags und Kontrollfluss unterscheiden können.
Wie Daten-Tags werden Logik-Tags unverändert im gerenderten MJML durchgereicht — Ihre Versandplattform wertet sie zum Versandzeitpunkt aus.
Beispiele für Logik-Tags nach Preset:
{% if customer.vip %}
<p>Exclusive offer just for you!</p>
{% endif %}
{% for item in cart.items %}
<p>{{item.name}} - {{item.price}}</p>
{% endfor %}{{#if hasSubscription}}
<p>Your plan renews on {{renewal_date}}</p>
{{/if}}
{{#each products}}
<p>{{this.name}}</p>
{{/each}}*|IF:VIP|*
<p>VIP discount applied</p>
*|END:IF|*%%[IF @subscriber_type == "premium"]%%
<p>Premium content here</p>
%%[ENDIF]%%Benutzerdefinierte Syntax
Wenn die integrierten Presets nicht zu Ihrer Plattform passen, definieren Sie eine benutzerdefinierte Syntax mit zwei Regex-Mustern -- eines für Daten-Tags und eines für Logik-Tags:
interface SyntaxPreset {
value: RegExp; // matches data tags like ${user.name}
logic: RegExp; // matches logic tags like $[IF ...]
}Beispiel für eine ${...} / $[...]-Syntax:
mergeTags: {
syntax: {
value: /\$\{.+?\}/g,
logic: /\$\[\s*(\w+).*?\]/g,
},
tags: [
{ label: 'User Name', value: '${user.name}' },
{ label: 'Order Total', value: '${order.total}' },
],
}Die value-Regex erkennt Daten-Tags. Die logic-Regex erkennt Kontrollflussanweisungen — die erste Erfassungsgruppe (\w+) extrahiert das Schlüsselwort (z. B. IF, FOR), das der Editor als Anzeigelabel verwendet.
Autovervollständigung
Wenn Benutzer den Syntax-Öffner (z. B. {{ für Liquid/Handlebars, *| für Mailchimp, %%= für AMPscript) innerhalb eines Titel- oder Absatzblocks eingeben, zeigt der Editor ein Popup mit übereinstimmenden Tags aus dem konfigurierten tags-Array an. Das Auswählen eines Eintrags (Mausklick, Enter oder Tab) fügt es als formatiertes Merge-Tag ein — dieselbe Form, die der Toolbar-Picker erzeugt. Esc oder ein Klick außerhalb schließt das Popup.
Die Filterung ist nicht groß-/kleinschreibungsabhängig und gleicht sowohl label als auch value ab. Die Liste ist auf 10 Ergebnisse begrenzt.
Die Autovervollständigung ist standardmäßig aktiviert. Sie wird automatisch deaktiviert, wenn:
tagsleer ist (keine Kandidaten zum Vorschlagen) odersyntaxeine benutzerdefinierte Regex ist (der Editor kann aus beliebigen Regex-Mustern keine Trigger-Zeichenkette ableiten).
Um sie explizit zu deaktivieren, setzen Sie autocomplete: false:
const editor = await init({
container: '#editor',
mergeTags: {
autocomplete: false,
tags: [
{ label: 'Vorname', value: '{{first_name}}' },
],
},
});Die Schaltfläche „Merge-Tag einfügen" in der Symbolleiste funktioniert weiterhin unabhängig von der Autovervollständigungs-Einstellung.
Integrierter Picker
Wenn Sie mergeTags.tags ohne onRequest-Callback konfigurieren, öffnet ein Klick auf die Schaltfläche „Merge-Tag einfügen" in der Rich-Text-Symbolleiste (oder neben einem Texteingabefeld in der Seitenleiste) ein integriertes modales Picker-Fenster. Der Picker listet jedes Tag aus tags auf, unterstützt Tastaturnavigation und bietet ein Suchfeld, das gegen label, value und description filtert.

Der Picker zeigt:
- das Label (fett)
- den rohen Wert (Monospace, gedimmt)
- die optionale Beschreibung (klein, gedimmt), sofern gesetzt
Wenn mindestens ein Tag ein group-Feld trägt, rendert der Picker sektionierte Überschriften in Einfügereihenfolge (der Reihenfolge in Ihrem tags-Array). Tags ohne group landen unter einer lokalisierten „Sonstige"-Überschrift. Wenn kein Tag eine group hat, rendert der Picker eine flache Liste — keine Überschriften, kein „Sonstige"-Eimer.
Während Sie tippen, werden Gruppen aufgelöst und die Liste gefiltert. Die Filterung ist nicht groß-/kleinschreibungsabhängig und gleicht Teilzeichenketten in label, value oder description ab. Beim Löschen der Suche wird das gruppierte (oder flache) Layout wiederhergestellt.
Ein-Schritt-Einfügen: Ein Klick auf eine Zeile oder das Drücken von Enter auf der hervorgehobenen Zeile fügt das Tag ein und schließt das Modal. Esc, das Schließen-Symbol im Header (×) oder ein Klick auf den Hintergrund schließen den Picker ohne Einfügen.
const editor = await init({
container: '#editor',
mergeTags: {
tags: [
{
label: 'Vorname',
value: '{{first_name}}',
group: 'Empfänger',
description: 'Persönliche Anrede',
},
{
label: 'Nachname',
value: '{{last_name}}',
group: 'Empfänger'
},
{
label: 'Unternehmen',
value: '{{company.name}}',
group: 'Konto'
},
{
label: 'Abmelde-URL',
value: '{{unsubscribe_url}}',
description: 'Gesetzlich vorgeschrieben (Anti-Spam)',
},
],
},
});Dynamisches Tag-Laden
Für große oder kontextabhängige Tag-Listen verwenden Sie den onRequest-Callback anstelle von (oder zusätzlich zu) einem statischen tags-Array. Der Editor ruft diese Funktion auf, wenn der Benutzer klickt, um ein Merge-Tag einzufügen. Verwenden Sie sie, um ein benutzerdefiniertes Picker-Modal zu öffnen, verfügbare Merge-Tags von Ihrer API abzurufen oder eine kontextbezogene Tag-Liste basierend auf dem aktuellen Benutzer zu erstellen. Geben Sie das ausgewählte MergeTag oder null zurück, um abzubrechen.
const editor = await init({
container: '#editor',
mergeTags: {
onRequest: async () => {
const tag = await showMyMergeTagPicker();
return tag; // MergeTag or null if cancelled
},
},
});Vorrangregel
Wenn Sie sowohl tags als auch onRequest angeben, hat onRequest Vorrang — die Schaltfläche „Merge-Tag einfügen" ruft immer Ihren Callback auf. Das statische tags-Array versorgt weiterhin die Autovervollständigungs-Vorschläge beim Tippen.
Merge-Tags in anderen Eingaben
Merge-Tags sind nicht auf Titel- und Absatzblöcke beschränkt. Der Editor erkennt und hebt Merge-Tags auch in anderen Blockeingaben hervor — Schaltflächentext, Schaltflächen-URL, Bild-URL, Bild-Alternativtext und Link-href-Werte. Das gleiche Label-Ersetzungs- und Tooltip-Verhalten gilt in diesen Feldern.
