A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/mifi/mjml-dynamic below:

mifi/mjml-dynamic: Dynamic JSON content for MJML templates

Dynamic JSON content for MJML templates

MJML is a great open source tool for building emails, however as developers we often want to include dynamic content in our emails. The problem is that MJML does not have any templating support (and they have no intention to.) This can be worked around by using placeholders in your MJML and then compiling the markup first using a templating engine like Handlebars, Pug etc, however what if we could generate the content dynamically using JavaScript! It turns out that MJML already supports rendering JSON markup instead of MJML. The problem is that there is no way to include partial JSON content, but mjml-dynamic solves this problem.

New MJML attribute: mj-replace-id

You include a special tag mj-replace-id="myId" into any of your mj- tags in your MJML document. This will allow you to process these tags programmatically or inject your own JSON MJML content into them, using a new replacers option for the mjml2html function.

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

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

      </mj-column>
    </mj-section>
  </mj-body>
</mjml>
New mjml2html option: replacers

The mjml2html() API of mjml-dynamic is exactly the same as the upstream mjml API, but there is an added option called replacers which is an object where each key corresponds to a mj-replace-id and the value is either null or an object with one or more of the following properties:

Property Type Description content string Change the text or HTML content of the element. attributes object<string,string> Change the HTML attributes of the element. children array<object> Change the element's MJML children elements (for example with mjml-react.) tagName string Change the tag to a completely different tag.

Any of the above replacers properties are optional. You may alternatively supply a function that receives the existing value as its only argument and returns the new value. This can be used to modify the existing values. content and attributes replacements are automatically escaped, however if you specify the functional content replacer, the response is not escaped.

If you specify null as the replacer's value instead of the above object, the matching node will be removed.

yarn add -D mjml mjml-dynamic
import mjml2html from 'mjml-dynamic';

const replacers = {
  myId: {
    tagName: 'mj-button',
    // these values are all automatically escaped:
    content: 'new text content', 
    attributes: { color: 'red', href: '&' },
  },
  removedId: null, // use null to completey remove the node
  // ... more `mj-replace-id`s
};

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" href="&amp;">
          new text content
        </mj-button>

      </mj-column>
    </mj-section>
  </mj-body>
</mjml>
Example: functional replacers
const replacers = {
  myId: {
    // Add an additional color attribute, while preserving the existing attributes:
    attributes: (attributes) => ({ ...attributes, color: 'red' },

    // Rewrite the HTML content:
    content: (content) => content.replace('{{something}}', 'something else'),
    // NOTE! mjml-dynamic does not automatically escape the replacement HTML here, so you need to do it yourself.
    // (You may use a template engine like handlebars for more sophisticated replacements)
  },
};
Example: list / loop (replacing children):

You can use this to include any kind of dynamic MJML as a node's children, and even loops to generate lists.

<mjml>
  <mj-body mj-replace-id="peopleList" />
</mjml>
import mjml2html from 'mjml-dynamic';

const people = [
  { name 'John Doe', age: 23 },
  { name 'Jane Doe', age: 34 },
  { name 'Satoshi Nakamoto', age: 99 },
]

const replacers = {
  peopleList: {
    children: [{
      tagName: 'mj-section',
      children: [{
        tagName: 'mj-column',
        children: people.map(({ name, age }) => ({
          tagName: 'mj-text',
          content: `${name} - ${age} yr`,
        })),
      }],
    }],
  },
};

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

This will output the equivalent of the following MJML document:

<mjml>
  <mj-body>
    <mj-section>
      <mj-column>
        <mj-text>
          John Doe - 23 yr
        </mj-text>
      </mj-column>
    </mj-section>
    <mj-section>
      <mj-column>
        <mj-text>
          Jane Doe - 34 yr
        </mj-text>
      </mj-column>
    </mj-section>
    <mj-section>
      <mj-column>
        <mj-text>
          Satoshi Nakamoto - 99 yr
        </mj-text>
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

Example to replace parts of your .mjml document with React code:

Assuming you have a template.mjml with an overall email layout that you can preview using official MJML tooling:

<mjml>
  <mj-body>
    <mj-include path="header.mjml" />

    <mj-section>
      <mj-column>
        <mj-text>Here is a list of people</mj-text>
      </mj-column>
    </mj-section>

    <mj-section>
      <mj-column mj-replace-id="peopleList" />
    </mj-section>

    <mj-include path="footer.mjml" />
  </mj-body>
</mjml>

Then you can render the contents of the element <mj-column mj-replace-id="peopleList"> using mjml-react:

import readFile from 'fs/promises';
import { parseXml } from 'mjml-dynamic';

const tableData = [
  { id: 1, name: 'Jane Doe' },
  { id: 2, name: 'John Doe' },
];

const mjml = renderToStaticMarkup((
  <MjmlTable>
    {tableData.map(({ id, name }) => (
      <tr key={id}>
        <td style={{ padding: '0 10px' }}>
          {name}
        </td>
      </tr>
    )}
  </MjmlTable>
));

const { json: reactJson } = parseXml(mjml);

const xml = await readFile('template.mjml', 'utf-8');

const replacers = {
  peopleList: {
    children: [reactJson],
  },
};

const { html } = mjml2html(xml, { replacers });
validateReplacers (default true)

Whether to check if all mj-replace-id in the MJML tree are specified in options, and check if all replacers exist in the MJML tree. This is useful in order to reduce the chance of coding mistakes.

See initial discussion here: mjmlio/mjml#2619


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4