---
title: Renderer
description: API-Referenz für @templatical/renderer — konvertiert Template-JSON zu MJML.
---

# Renderer

`@templatical/renderer` konvertiert Templatical-Template-JSON in MJML. Funktioniert sowohl in Browser- als auch in Node.js-Umgebungen.

Der Renderer erzeugt ausschließlich MJML. Um MJML für den E-Mail-Versand zu HTML zu kompilieren, verwenden Sie eine beliebige MJML-Bibliothek ([mjml](https://www.npmjs.com/package/mjml) für Node.js, [spatie/mjml-php](https://github.com/spatie/mjml-php) für PHP usw.).

::: code-group

```bash [npm]
npm install @templatical/renderer
```

```bash [pnpm]
pnpm add @templatical/renderer
```

```bash [yarn]
yarn add @templatical/renderer
```

```bash [bun]
bun add @templatical/renderer
```

:::

## `renderToMjml(content, options?)`

Rendert ein `TemplateContent`-Objekt zu einem MJML-String. Gibt ein `Promise<string>` zurück – asynchron, damit benutzerdefinierte Blöcke (deren Auflösung asynchrone Arbeit erfordern kann) inline gerendert werden können.

```ts
import { renderToMjml } from '@templatical/renderer';

const mjml = await renderToMjml(templateContent);
```

**Parameter:**

| Parameter | Type | Beschreibung |
|-----------|------|-------------|
| `content` | `TemplateContent` | Das zu rendernde Template |
| `options` | `RenderOptions` | Optionale Rendering-Konfiguration |

**Rückgabewert:** `Promise<string>` -- MJML-Markup

## RenderOptions

```ts
interface RenderOptions {
  locale?: string;
  layout?: TemplateContent;
  customFonts?: CustomFont[];
  defaultFallbackFont?: string;
  allowHtmlBlocks?: boolean;      // Standard: true
  customBlocks?: CustomBlockDefinition[];
  renderCustomBlock?: (block: CustomBlock) => Promise<string>;
  blockRenderers?: BlockRendererMap;
  getCustomBlockStylesheet?: (customType: string) => string | undefined | null;
  socialIconsBaseUrl?: string;
}
```

| Option | Default | Beschreibung |
|--------|---------|-------------|
| `locale` | `settings.locale` | Wählt die Template-Version; eine unbekannte Version lehnt mit `unknown_locale` ab. |
| `layout` | -- | Vom Integrator bereitgestellter Rahmen mit genau einem Slot. Darf eigene `settings.locales`, Block-`l10n` und `settings.l10n` enthalten, auch in Wrapper-Kindern. Vor dem Zusammensetzen wird es mit `missing: "default"` für die angefragte Sprache projiziert; fehlt diese dem Layout, gilt dessen Standardsprache. Siehe [Layout](/de/guide/layout). |
| `customFonts` | `[]` | Definitionen benutzerdefinierter Schriftarten für `<mj-font>`-Deklarationen in der gerenderten Ausgabe |
| `defaultFallbackFont` | `'Arial, sans-serif'` | Fallback-Stack, der an eine benutzerdefinierte Schriftart ohne eigenen `fallback` oder an eine einzelne, nicht eingebaute Schriftfamilie angehängt wird. Ein vollständiger Stack wird unverändert ausgegeben. |
| `allowHtmlBlocks` | `true` | Auf `false` setzen, um HTML-Blöcke aus der Ausgabe zu entfernen |
| `customBlocks` | -- | `CustomBlockDefinition[]` für Headless-Rendering. Bei gleichen Typen gewinnt die letzte Definition; unbekannte Typen verwenden gespeichertes `renderedHtml` und `renderedStylesheet`. Bei vorhandenen Blöcken ist der optionale Peer `liquidjs` `^10.30.1` erforderlich. Siehe den [Leitfaden für benutzerdefinierte Blöcke](/de/guide/custom-blocks). |
| `renderCustomBlock` | -- | Wandelt benutzerdefinierte Blöcke in HTML um. Wird einmal pro Block aufgerufen. Der Editor übergibt dies über `editor.toMjml()`. Nicht mit `customBlocks` kombinierbar. Wenn keine der beiden Optionen übergeben wird, verwendet jeder benutzerdefinierte Block `renderedHtml` (falls vorhanden). |
| `blockRenderers` | `{}` | Typbezogene Renderer-Overrides, keyed nach `block.type`. Ein Countdown-GIF-Backend nutzt dies. Ein Override übernimmt die Prüfung auf „auf allen Viewports ausgeblendet“. |
| `getCustomBlockStylesheet` | -- | `(customType) => string \| undefined \| null`. Wird einmal pro eindeutigem `customType` aufgerufen. Nicht mit `customBlocks` kombinierbar. Eine gelistete Definition entscheidet über das Stylesheet ihres Typs, auch wenn keines ausgegeben wird; unbekannte Typen verwenden gespeichertes `renderedStylesheet`. Ein übergebener Resolver entscheidet für jeden Typ und ignoriert gespeicherte Kopien. |
| `socialIconsBaseUrl` | versionsgebundene jsDelivr-URL | Basis-URL (ohne abschließenden Schrägstrich) für die PNG-Assets der Social-Media-Icons. Wird pro Icon zu `${baseUrl}/${dir}/${platform}.png` aufgelöst, wobei `dir` der Stil ist, bei einem `iconTone` von `dark` oder `light` gefolgt von `-${tone}`. Siehe [Social-Media-Icons](#social-media-icons) unten. |

`locale?: string` wählt eine Template-Sprachversion; ohne Angabe wird `settings.locale`, der Standard, gerendert. Unbekannte Versionen lehnen mit `SdkError`-Code `unknown_locale` ab. Die Projektion entfernt ausgeblendete Blöcke, wendet Text und Überschreibungen an und setzt MJML-`lang` und `dir`. Siehe [Lokalisierte Templates](/de/guide/localized-templates#eine-sprache-rendern).

### Benutzerdefinierte Blöcke

Headless-Aufrufer übergeben dieselben Definitionen, die sie im Editor registrieren:

```ts
import { renderToMjml } from '@templatical/renderer';
import type { CustomBlockDefinition, TemplateContent } from '@templatical/types';

export async function renderTemplate(content: TemplateContent, definitions: CustomBlockDefinition[]) {
  return renderToMjml(content, { customBlocks: definitions });
}
```

Für einen eigenen Resolver verwenden Sie die gemeinsame Liquid-Factory:

```ts
import * as liquidjs from 'liquidjs';
import { createCustomBlockLiquid } from '@templatical/types';
const liquid = createCustomBlockLiquid(liquidjs);
```

Fallback, genaue Konflikte und Fehlermeldung bei fehlendem Peer sowie die festen Optionen der Factory stehen im [Leitfaden für benutzerdefinierte Blöcke](/de/guide/custom-blocks). <code v-pre>{{ body | raw }}</code> erhält HTML aus einem dafür vorgesehenen Feld. Setzen Sie Attributwerte immer in Anführungszeichen und validieren Sie URL-Schemata aus nicht vertrauenswürdigen Quellen. Nur der Editor-Canvas bereinigt den gerenderten Block; die E-Mail-Ausgabe behält das HTML des Templates.

### Social-Media-Icons

Social-Icon-Blöcke werden als `<img src="…/{dir}/{platform}.png">` ausgegeben. `dir` ist bei Markenfarben der Icon-Stil (`circle`) und bei einem `iconTone` von `dark` oder `light` `{style}-{tone}` (`circle-dark`). Der Standardwert von `socialIconsBaseUrl` verweist auf den versionsgebundenen jsDelivr-Mirror von `@templatical/renderer`, der vorgerasterte PNGs (jede `SocialPlatform` × 6 Stile × 3 Farbtöne) mit dem Paket ausliefert:

```
https://cdn.jsdelivr.net/npm/@templatical/renderer@<version>/assets/social/{dir}/{platform}.png
```

**Warum PNGs.** Outlook Desktop (Word-Rendering-Engine) unterstützt kein SVG und lehnt base64-Daten-URIs in `<img src>` ab. Gehostete PNGs sind das einzige Format, das in allen gängigen E-Mail-Clients zuverlässig dargestellt wird.

**Warum versionsgebunden.** E-Mails sind Archivinhalt — Empfänger öffnen Nachrichten Monate oder Jahre nach dem Versand. Die Versionsbindung friert die Icon-Darstellung zum Renderzeitpunkt ein, sodass ein späteres Redesign oder ein Regressionsfehler im Paket bereits zugestellte E-Mails nicht rückwirkend beschädigt. Außerdem entfällt eine 302-Weiterleitung pro Icon und es können langlebige, unveränderliche Cache-Header gesetzt werden.

**Selbst hosten.** Überschreiben Sie `socialIconsBaseUrl`, um die Assets über Ihr eigenes CDN auszuliefern — nützlich für Air-Gapped-Umgebungen, markenspezifische Themen oder um die Abhängigkeit von jsDelivr zu entfernen:

```ts
const mjml = await renderToMjml(content, {
  socialIconsBaseUrl: 'https://cdn.example.com/email-assets/social',
});
```

Die exakten Dateinamen, die der Renderer erwartet, sind `{dir}/{platform}.png`, wobei `dir` ein `style` aus `solid | outlined | rounded | square | circle | plain` ist, für diese Farben gefolgt von `-dark` oder `-light` (ein Icon in Markenfarbe hat kein Suffix), und `platform` einer von `facebook | twitter | instagram | linkedin | youtube | tiktok | pinterest | email | whatsapp | telegram | discord | snapchat | reddit | github | dribbble | behance | website` ist. Die ausgelieferten 144×144-PNGs sind ein sinnvoller Ausgangspunkt, wenn Sie sie spiegeln möchten.

Das Paket exportiert außerdem `DEFAULT_SOCIAL_ICONS_BASE_URL`, falls Sie URLs gegen denselben Standardwert komponieren möchten:

```ts
import { DEFAULT_SOCIAL_ICONS_BASE_URL } from '@templatical/renderer';
```

## Hilfsfunktionen

Der Renderer exportiert außerdem Hilfsfunktionen:

```ts
import {
  escapeHtml,
  escapeAttr,
  convertMergeTagsToValues,
  isHiddenOnAll,
  toPaddingString,
  renderBlock,
  getCssClassAttr,
  getCssClasses,
  getWidthPercentages,
  getWidthPixels,
  fluidOnMobileAttr,
  DEFAULT_SOCIAL_ICONS_BASE_URL,
  RenderContext,
} from '@templatical/renderer';
```

### `escapeHtml(text)`

Maskiert HTML-Entitäten (`<`, `>`, `&`, `"`, `'`) in einem String. Verwenden Sie dies, wenn Sie Benutzerinhalte in HTML einfügen:

```ts
escapeHtml('<script>alert("xss")</script>');
// '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'
```

### `escapeAttr(text)`

Maskiert einen String für die sichere Verwendung in HTML-Attributwerten:

```ts
const alt = escapeAttr('Photo of "sunrise" at O\'Hare');
// 'Photo of &quot;sunrise&quot; at O&#x27;Hare'
```

### `convertMergeTagsToValues(html)`

Konvertiert HTML-Spans für Merge-Tags (vom Rich-Text-System des Editors intern verwendet) zurück in ihre einfache Textsyntax. Der Editor speichert Merge-Tags als `<span data-merge-tag="...">`-Elemente; diese Funktion entfernt die Spans und lässt die rohe Merge-Tag-Syntax übrig:

```ts
import { convertMergeTagsToValues } from '@templatical/renderer';

// Eingabe: internes HTML-Format des Editors
const editorHtml = '<span data-merge-tag="{{ first_name }}">First Name</span>';

const cleaned = convertMergeTagsToValues(editorHtml);
// Ausgabe: '{{ first_name }}'
```

::: tip
Sie müssen diese Funktion normalerweise nicht direkt aufrufen — der Renderer ruft sie intern beim Verarbeiten von Title- und Paragraph-Blöcken auf. Sie wird für fortgeschrittene Anwendungsfälle exportiert, in denen Sie mit Editor-HTML außerhalb der normalen Rendering-Pipeline arbeiten.
:::

### `isHiddenOnAll(block)`

Gibt `true` zurück, wenn bei der `visibility` eines Blocks alle Viewports auf `false` gesetzt sind. Nützlich, um Blöcke zu überspringen, die überhaupt nicht gerendert werden sollen:

```ts
if (isHiddenOnAll(block)) {
  // Diesen Block vollständig überspringen
}
```

### `toPaddingString(padding)`

Konvertiert einen `SpacingValue` in einen CSS-Padding-String:

```ts
toPaddingString({ top: 10, right: 20, bottom: 10, left: 20 });
// '10px 20px 10px 20px'
```

### `renderBlock(block, context)`

Rendert einen einzelnen Block in seine MJML-Darstellung. Wird intern von `renderToMjml()` verwendet, aber für fortgeschrittene Anwendungsfälle exportiert, in denen Sie einzelne Blöcke rendern müssen.

### `RenderContext`

Das an Block-Renderer übergebene Kontextobjekt. Enthält Rendering-Optionen, Schriftart-Konfiguration und zwei Breiten:

| Feld | Wert |
|---|---|
| `containerWidth` | Der Anteil der Spalte an der Body-Breite, ohne Padding und Rahmen um sie herum. Ein Bild oder Video mit `'full'` wird in dieser Breite ausgegeben, und MJML begrenzt es auf seine tatsächliche Box. |
| `contentWidth` | Die ganzen Pixel, die MJML dem Inhalt der Spalte gibt: die Body-Breite abzüglich des seitlichen Paddings und Rahmens von Wrapper-Band und Sektion, davon der Prozentanteil der Spalte, abgerundet. Breitenabhängige Entscheidungen lesen diesen Wert. |

In einer [Hero-Sektion](/de/guide/sections-and-columns#hero) hat der Inhalt keine Spalte: `containerWidth` ist die Box des Heros (die Body-Breite abzüglich der Bänder um ihn herum) und `contentWidth` diese Box abzüglich des seitlichen Paddings des Heros. Ein Hero zeichnet keinen Rahmen, daher wird keiner abgezogen.

`withContainerWidth(width, contentWidth = width)` gibt eine Kopie für einen schmaleren Container zurück.

### `fluidOnMobileAttr(block, context)` {#fluid-on-mobile-attr}

Gibt `' fluid-on-mobile="true"'` für ein Bild zurück, das seine Spalte auf dem Desktop füllt, sonst `''`. Ein Bild füllt seine Spalte, wenn seine `width` `'full'` ist oder eine Pixelbreite, die `context.contentWidth` abzüglich des seitlichen Paddings und Rahmens des Blocks erreicht oder überschreitet. Siehe [Breite auf Smartphones](/de/guide/images#width-on-phones).

Die eingebauten Bild- und Video-Renderer verwenden sie. Eine `blockRenderers`-Überschreibung, die ein eigenes `mj-image` ausgibt, ruft sie ebenfalls auf; ohne das Attribut behält das Bild auf dem Smartphone seine Desktop-Breite:

```ts
blockRenderers: {
  image: (block, ctx) => {
    const image = block as ImageBlock;
    const width = image.width === 'full' ? ctx.containerWidth : image.width;
    return `<mj-image src="${escapeAttr(image.src)}" width="${width}px"${fluidOnMobileAttr(image, ctx)} />`;
  },
},
```

### `getCssClassAttr(block)` / `getCssClasses(block)`

Erzeugen CSS-Klassen-Attribute aus den Sichtbarkeitseinstellungen eines Blocks. Wird intern für responsives Ausblenden verwendet.

### `getWidthPercentages(layout)` / `getWidthPixels(layout, containerWidth)`

Berechnen Spaltenbreiten für ein gegebenes `ColumnLayout`. Gibt ein Array von Prozent- oder Pixelwerten pro Spalte zurück.

### `DEFAULT_SOCIAL_ICONS_BASE_URL`

Der Standardwert von `RenderOptions.socialIconsBaseUrl` — die versionsgebundene jsDelivr-URL, die auf die in diesem Paket mitgelieferten PNGs der Social-Media-Icons verweist. Siehe [Social-Media-Icons](#social-media-icons).

## MJML zu HTML kompilieren

Nach dem Rendern in MJML kompilieren Sie mit einer beliebigen MJML-Bibliothek zu HTML:

```ts
import { renderToMjml } from '@templatical/renderer';
import mjml2html from 'mjml';

const mjml = await renderToMjml(templateContent);
const { html } = mjml2html(mjml);

// html ist bereit zum Versand über Ihren E-Mail-Dienst
```

Weitere Informationen zur Rendering-Pipeline finden Sie unter [Wie das Rendering funktioniert](/de/getting-started/how-rendering-works).
