MJML - Template Interpolation, Dynamic Data, Context
Asked Answered
S

2

20

After a lot of searches, I am having difficulties in finding how:

  1. MJML handles dynamic data and template interpolations

I was expecting something like:

import { mjml2html } from 'mjml';

const context = {
  message: 'Hello World'
};

const view = mjml2html(template, context);
<mjml>
  <mj-body>
    <mj-container>
      <mj-section>
        <mj-column>
          <mj-text>{message}</mj-text>
        </mj-column>
      </mj-section>
    </mj-container>
  </mj-body>
</mjml>
Stucker answered 30/3, 2017 at 7:49 Comment(4)
MJML doesn't handle any templating. If you want templates, use a template engine to render to MJML.Malmsey
could you explain better?Stucker
Did you get this down? I'm stuck trying to figure out how to do dynamic data like in a for each loop. @StuckerDowson
I solved it by not using mjml. That was a critical feature and rendering twice wasn't ideal... so we just went for much more practicals react components!Stucker
M
47

MJML doesn't handle any templating. If you want templates, use a template engine such as handlebars to render to MJML.

import { compile } from 'handlebars';
import { mjml2html } from 'mjml';

const template = compile(`
<mjml>
  <mj-body>
    <mj-container>
      <mj-section>
        <mj-column>
          <mj-text>{{message}}</mj-text>
        </mj-column>
      </mj-section>
    </mj-container>
  </mj-body>
</mjml>
`);
const context = {
    message: 'Hello World'
};
const mjml = template(context);
const html = mjml2html(mjml);
Malmsey answered 30/3, 2017 at 8:24 Comment(3)
There are performance issues because of the double round trip.Stucker
You're not going to get anything better due to MJML not supporting templates.Malmsey
This mjml utility library called mjml-utils works good for me.Atonsah
T
2

Having gone through the same process of trying to find the best way to add dynamic content to my MJML files while still being able to preview the templates using existing tooling, initially I just used handlebars, but after adding more complex content structures it started to get messy.

It turns out that MJML is just simple XML and maps quite well to JSON. Rendering from JSON is already supported by MJML, but only rendering the whole document (not parts of the document.)

I came up with a technique that allows rendering parts of a .mjml file programmatically, by manipulating the XML (JSON) structure programmatically (so no need for manual escaping or worries about XSS/injection), and I created a module mjml-dynamic to solve this problem.

npm i --save mjml-dynamic mjml

Example:

<mjml>
  <mj-body>
    <mj-section>
      <mj-column>

        <mj-button mj-replace-id="myId">
          Some text
        </mj-button>

      </mj-column>
    </mj-section>
  </mj-body>
</mjml>
import mjml2html from 'mjml-dynamic';
import readFile from 'fs/promises';

const replacers = {
  myId: {
    content: 'new text content',
    attributes: { color: 'red' },
  },
};

const mjml = await readFile('template.mjml');

const { html } = mjml2html(mjml, { replacers });

This will output the equivalent of the following MJML document:

<mjml>
  <mj-body>
    <mj-section>
      <mj-column>

        <mj-button color="red">
          new text content
        </mj-button>

      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

You can even use it in combination with mjml-react to render parts of your template using React.

See more examples here

Titanothere answered 15/1, 2023 at 8:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.