Mjml: Ability to add custom properties

Created on 26 Apr 2016  ·  89Comments  ·  Source: mjmlio/mjml

I'd like the ability to add custom properties and values.

Currently I build a lot of editable templates for clients to use in mailchimp, it would be preferable to define the editable areas in the mjml rather than having to retro-fit it to the compiled html.

For instance:
<mj-text color="#ffffff" font-size="28" align="center" padding-top="40" mc:edit="title">

Feature request

Most helpful comment

Hi @everyone-on-this-thread, following this discussion we finally released a feature allowing to add any attribute to the generated html. You can install the beta with the next tag, i.e. npm i mjml@next
Here is the documentation for this : https://github.com/mjmlio/mjml/blob/master/packages/mjml-head-html-attributes/README.md

All 89 comments

Perhaps this format would work?
<mj-text color="#ffffff" font-size="28" align="center" padding-top="40" prop="mc:edit,title" prop="id,sample_id">

I don't know if we can implement this because of how components work. One component doesn't equal one line of html code. So I don't know where to place custom properties...

This problem seems similar to #324 in their nature.
My recommendation for the the attribute placement would be the outermost html element not encapsulated by if mso elements, but it's a tough choice to make...

In case of mailchimp, the documentation seems to support what I've recommended, but I cannot be certain without actually trying it out.

Example for mj-text

<!--[if mso | IE]>
  <table border="0" cellpadding="0" cellspacing="0"><tr><td style="vertical-align:top;width:600px;">
<![endif]-->
  <div id="sample_id" mc:edit="title" aria-labelledby="mj-column-per-100" class="mj-column-per-100" style="vertical-align:top;display:inline-block;font-size:13px;text-align:left;width:100%;">
    <table cellpadding="0" cellspacing="0" width="100%" border="0">
      <tbody>
        <tr>
          <td style="word-break:break-word;font-size:0px;padding:10px 25px;" align="left">
            <div style="cursor:auto;color:#F45E43;font-family:helvetica;font-size:20px;line-height:22px;">Hello World</div>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
<!--[if mso | IE]>
  </td></tr></table>
<![endif]-->

@iRyusa sorry to bother you, but can you give an ETA on this? Or can I help in any way to speed things up?

I quote myself, atm we have no idea to implement that :/

Each element is unique and has no root element. So it's hard to add such generic element.

I've partially resolved this issue by creating custom components (based on the core components) which allow the properties I need.

mc-section
mc-image

@homerjam I updated your code to add support for mc:edit.

mc-section.js (update)

It was just a simple edit, but I've been using it for a while in my own projects so...what the hell. Upload it here to Github.

@PatriotRDX Added css-class to your mc-section.js

Now im needing to do the same thing with the mj-wrapper as my repeatables need to include rows and you cant do that with only mj-section. Being able to add custom props would be great for MJML!

@absentees I ended up moving to Foundation for Emails 2 and our work paid for a class from Zurb that the design people could use to learn how to use it.

@PatriotRDX oh nice. Hadn't checked out Foundation, thanks!

Is there a current status for this feature on MJML4? Or documentation on how to write custom components for MJML4.

Two issues here :

  • We still don't know how the syntax could look like.
  • There's still the issue of where you could apply them, as a component isn't rendered as one single html node.

Mailchimp support in MJML would be a killer argument for MJML! I would appreciate this workflow.

@iRyusa For my purposes the outermost element would be the ideal, but idk for the mailchimp users though... In my case, we need a way to link the mjml source with the generated html, so basically even ids would be wonderful...

@blackfyre each body tag takes a css-class attribute which will be passed as a class to the root HTML tag created from that MJML tag.

Could a potential solution look like this?

<mj-text 
  color="#ffffff" 
  font-size="28" 
  align="center" 
  padding-top="40"
  custom-attrs={
    'mc:edit': 'foobar',
    hello: 'world',
    active: true,
    archived: false,
    'no-value-attr-1': null,
    'no-value-attr-2': undefined,
  }
>

the issue is always the same @charlex, it's not about how to handle them on the MJML tag, but rather where to output those custom attributes in the HTML (1 MJML tag = n HTML tags)

I do think there should be solution proposals and the community should vote on it...
My proposal is that the custom attributes should be added to the outermost uncommented element of the mj-* element.

Ok. In the case of Mailchimp attributes, this would work for editing a text, but it wouldn't work for editing an image (as the Mailchimp attribute needs to be on the img tag). Don't you think it's a problem to have something that works in certain cases but not in others?

@ngarnier yes, but no!

Pretty sure 99% of mjml users with this issue just need a few of the core elements to work with MailChimp. Generally it's clear which element should be passed the attributes - and where it's not we could vote. Would it not be best to create 'special properties' for certain elements rather than trying to find a perfect solution for all that simply doesn't exist?

Updated Mailchimp compatible components for MJML v4:

mc-section
mc-image

const mjml2html = require('mjml');
const { registerComponent } = require('mjml-core');
const { registerDependencies } = require('mjml-validator');

// babel compiled components
const McSection = require('./mc-section.js');
const McImage = require('./mc-image.js');

registerComponent(McSection);
registerComponent(McImage);
registerDependencies({
  'mc-section': ['mj-column', 'mj-group', 'mj-raw']
  'mj-column': ['mc-image'],
  'mj-hero': ['mc-image'],
});

console.log(mjml2html(templateString));

Personally, I would love to see custom attributes supported on the root element of select components (mj-text, mj-image, mj-section, mj-column in particular). I understand that it then becomes something that does not apply to all of the available components, but the flexibility this would provide would be very handy indeed!

MailChimp is one example, but then there's Campaign Monitor which also has its own custom attributes for defining editable regions.

Thanks for MJML - just discovered today and I think it's awesome!

https://github.com/bastienrobert/mjml-mailchimp, forked from @homerjam, I added some new components

EDIT (26/06) : I'm going to fork MJML lib to fix this problem, PR ASAP, will edit this post when it'll be ready

Hi, just opened the #1263 (referenced here) and if you have some recommandations, I will take them 👍

@bastienrobert appreciate the effort! I think it might be best to keep discussion here as the fundamental approach is yet to be agreed.

If I understand correctly your approach would require modifying each component, no?

I believe the ideal solution is a core API that allows custom attributes on the root element of every component. The API could then either be disabled per component or given an alternative element apply the attributes to.

Yes, something like the same way but directly implemented on mjml-core, in the Component class or something like this. I'll investigate!

Yup the issue remain the same, as @homerjam mentioned.

I have a small concern about adding a JSON syntax right into a DOM elements too. Mixing too many syntax can be a bit misleading for users

Yep, another way could be like . But it’ll need to get all dataset like those and it could be a problem for specific data attr, like with mail chimp integration which use mc:edit or some custom data attr with weird syntax.

Custom properties (not attributes specifically) is becoming a bit of a deal breaker for me too.

All links in my emails require a URL query adding to the end. Changing them across all includes can be a bit of a fiddle. Something like:

<mj-include path="./banner.mjml" props="{trackingId: '8744'}" />

banner.mjml

    <mj-section mj-class="hero">
      <mj-column>
        <mj-image
         src="assets/email-banner.jpg"
         href="http://www.blahblahblah.com/?trackingId={{props.trackingId}}"
         />
      </mj-column>
    </mj-section>

...would be pretty handy over the course of a multiple-email campaign. This could presumably be used for attributes also:

    <mj-section mj-class="hero">
      <mj-column>
        <mj-image
          src="assets/email-banner.jpg"
          href="http://www.blahblahblah.com/?trackingId={{props.trackingId}}"
          {{#if props.altText}}alt="{{props.altText}}"{{/if}}
          />
      </mj-column>
    </mj-section>

Apologies if this idea has beed vetoed already. Mainly flagging a use case for custom properties.

You're mixing up templating & custom attributes @simonlayfield . What you need is a templating lang here like handlebars/mustache/pugjs, we already mentioned that MJML is only a markup language like HTML and we don't want to introduce again a new syntax for templating

Hi, I have one more use case for data attributes:

We use http://sparkpost.com for sending e-mails, and it supports tagging links with a custom attribute (<a href="..." data-msys-linkname="footer-logo">...</a>.

Afterwards it's easy to collect statistics about which linknames were clicked and how much.

What's missing for me now is having these attributes on links in <mj-button> and <mj-image>.

This is a very good example illustrating the issue we've been pointing out since the beginning as:

  • in your case, the need is to pass a custom attribute from mj-image to the HTML a tag wrapping an image (in case there is a href)
  • in one of the previous use-cases, the need is to pass a custom attribute from mj-image to the HTML img tag

We can clearly see that based on the use case, the need will be different and so we have no way to anticipate which HTML tag the custom MJML attributes should be passed to.

PS: I think there are better ways to track links than having to pass custom HTML attributes to a tags, for example using URL parameters (which is very standard)

@ngarnier Thanks - yep, I am now forking mj-button and mj-image, but then I'll be responsible for maintaining it.

I also suggested to sparkpost to support adding the data-msys-linkname to url, just like utm_ tags. The only theoretical problem with that is that urls belong to the app (and some very badly written apps can be broken by adding extra url params).

Third way could be a post-processing pass on resulting html, but then it's hard to discern which link is which.

Fyi, I made a working sample of creating custom components that extend the built-in ones, with mjml 4.1.2: https://github.com/tkafka/mjml-custom-components-sample

+1 for tighter MailChimp integration 👍

+1 for tighter MailChimp integration

Please refrain from commenting to add "+1". It doesn't help and doesn't provide any solution to the problems raised before, especially:
https://github.com/mjmlio/mjml/issues/200#issuecomment-378845161
https://github.com/mjmlio/mjml/issues/200#issuecomment-418287553

I just like to use mjml in gulp and use atributes from mailchimp

We totally understand the need and it's not that we don't want to do it. However, like explained in different messages on this issue, we haven't found any good way to do it from a functional point of view. And yes, as much as some of you dislike it, adding +1 doesn't solve the situation.

Let me explain the problem again: one single MJML tag generates several HTML tags, but we cannot guess on which HTML tag the custom attribute should be added.

Example:

  • Sparkpost tagging links on images: add a custom attribute on mj-image that should be added to the a HTML tag generated from mj-image
  • Mailchimp's editable images: add a custom attribute on mj-image that should be added on the img HTML tag generated from mj-image

You can see here that for a same MJML tag (mj-image), different users expect their custom attribute to behave differently and be added to different HTML tags. And this is just 2 use-cases for one single component, but you can multiply that by as many use-cases as there are, and as many components as there in MJML.

How are we supposed to handle that?

Maybe create new tags just for mailchimp can help on this matter !

As the framework is open source, feel free to fork components if you want to add custom attributes as done here https://github.com/mjmlio/mjml/issues/200#issuecomment-418386904

But it's not a future-proof approach, so it's not an option for us.

Ok so what about this "idea", it might be a start, or a dead end.

Let's say we add a new "global" attribute that we call something like "attach" and can use a css selector to apply some stuff.

<mj-text attach="div;data-read-only;true">content...</content> and then we use something like cheerio again to "apply" the attribute given the selector. It might be flexible enough to attach to anything ex <mj-button attach="tr table td;contenteditable;true">....</mj-button>

You can also chain them in a single attach following the same pattern <mj-text attach="td;data-article;1;div;contenteditable;true;table;data-useless;true">

We have to reintroduce cheerio which lead _sometime_ with templating stuff/non valid html into infinite loop or altered output. Given that we never really identified how to reproduce those issue it can be a real drawback.

We might avoid altered content by just lazy interpreting children in all MJML components using template literals but it would require to do a major version (MJML5...).

And it would also need to change a bit how we render children in MJML components to take into account contextual surrounding elements (like mj-column automatically wraps any non raw element in a tr/td... and it's not the single element to do that).

What do you think ...?

It seems a bit complicated, don't you think?

It's over 3 years since this issue was raised. It seems a perfect solution doesn't exist. The options:

  • Use forked/custom components (works)
  • Pollute the library with platform specific attributes (ie. for MailChimp - seems a bad idea/unlikely)
  • Add platform specific components to the library (would add significant maintenance work)

Well for 3 years no one really dive into this issue. There's few proposal but nothing concrete. If it's a feature done inside mjml-core API then it would be done once and for all.

I think it is a good idea, how about to expand it a little bit

<mj-style inline="attach">
  .cus_attr_1{
    contenteditable: true;
    cm_donconvertlink: "";
  }
  .cus_attr_2{
    key2: val2;
  }
</mj-style>

<mj-image attach="[a,img]=[cus_attr_1];[td,tr]=[cus_attr_2]">

will generate

<img contenteditable="true" cm_donconvertlink="" />
<a contenteditable="true" cm_donconvertlink=""></a>
<tr key2="val2">
<td key2="val2">


Isn't this a bit weird to write ? I feel like there's very few cases where you'd want to reuse a set of custom attributes ?

@homerjam yes but using forked/custom components is a big mess: it is necessary that components remains up to date, it adds a big amount of work on the side of the end-user


@tianhsky @iRyusa I like this solution, in my opinion it is rather readable, even if there's very few cases where you'd want to reuse a set of custom attributes

Isn't this a bit weird to write ? I feel like there's very few cases where you'd want to reuse a set of custom attributes ?

The css approach is just one idea to define custom attrs, I think having some flexibility there will benefit some users. I do agree define var using css syntax is weird and it is not common to reuse a set of attrs.

or it could be

<mj-attributes>
  <mj-custom-attr class="cus_attr_1" name="key1" val="" />
  <mj-custom-attr class="cus_attr_2" name="key2" val="" />
</mj-attributes>

<mj-image attach="[a,img]=cus_attr_1;[td,tr]=cus_attr_2;">

Based on my limited knowledge I think @iRyusa solution could be implemented, I'd be for it.

The ideal would be to add support for the major providers/platforms specific template syntax to the core and add the appropriate documentation. Although this would be beneficial for a lot of users it'd be a large burden for the maintainers.

or it could be

<mj-attributes>
  <mj-custom-attr class="cus_attr_1" name="key1" val="" />
  <mj-custom-attr class="cus_attr_2" name="key2" val="" />
</mj-attributes>

<mj-image attach="[a,img]=cus_attr_1;[td,tr]=cus_attr_2;">

This is interesting 🤔

Is your proposal to add a component which decorates the output with the custom attributes after compilation?

or it could be

<mj-attributes>
  <mj-custom-attr class="cus_attr_1" name="key1" val="" />
  <mj-custom-attr class="cus_attr_2" name="key2" val="" />
</mj-attributes>

<mj-image attach="[a,img]=cus_attr_1;[td,tr]=cus_attr_2;">

This is interesting 🤔

Is your proposal to add a component which decorates the output with the custom attributes after compilation?

correct, in this case, the output will be something like this

<img key1="" />
<a key1=""></a>
<tr key2="">
<td key2="">

So if you have a 300+ lines of templates you'll have to go back on top to check the custom attributes you're using on a single node element ? And what about CSS selector ?

Hi all, I was thinking about this too, and it seems to me that there are two different problems:

  1. We want to define, where in the element's template to add the custom attribute - this should happen once as I can imagine it would work for eg. all links in the email. I imagine this as an analogy for eg. Swift or C# extensions - a way to add property to an existing component without changing its code.

  2. We want to define a specific value of the attribute - this needs to be specified for each MJML element specifically, and should have a simple key="value" syntax.

As for 1), I'd like to borrow @homerjam's idea - something like this would tell us that we are extending mjml-image with a new link-track-id property, which will be added to a (this would be a css selector), and the default value is empty (= by default the custom attribute won't be added).

This bit could be reusable - I'd put this declaration into some common.mjml file which I'd include from all my templates:

<mj-custom-attributes>
  <mj-custom-attribute element="mjml-image" attach="table > tr > td a" name="link-track-id" defaultValue="" />
</mj-custom-attributes>

As for 2), I'd then use a newly defined attribute on elements where I want to add it:

<mjml-image src="..." href="..." link-track-id="header-brand-link" />

This would then render as a mjml-image, which has extra link-track-id="header-brand-link" attribute on the inner <a> link.

What do you think?

Why not just merge attach declaration (like we do for css class) and use mj-class instead ? We already have something like this in the markup so let's reuse that ?

<mj-attributes>
  <mj-class name="tracking-link" attach="tr td a;data-tracking-id;24" />
  <mj-class name="edit-image" attach="img;data-editable;true" />
</mj-attributes>
...
<mj-image mj-class="tracking-link edit-image"  /> 

@iRyusa I like the idea of reusing existing mj-class tag for that, but I really dislike that we are creating a new DSL (the tr td a;data-tracking-id;24 is non-transparent). HTML/XML has a very flexible attribute system just for that, imo attach-element="tr td a" attach-attr="data-tracking-id" attach-value="24" is much more readable, debuggable and writable, than attach="tr td a;data-tracking-id;24".

The same goes for use - why not just write <mj-image mj-class="tracking-link" data-tracking-id="edit-image" /> instead of <mj-image mj-class="tracking-link edit-image" />?

Perhaps some combination of the two.

<mj-custom-attr>
  <mj-custom-attr id="edit-link" selector="table > tr > td a" name="mc:edit" value="" />
  <mj-custom-attr id="hide-link" selector="table > tr > td a" name="mc:hideable" value="" />
</mj-custom-attr>
<!-- Full version -->
<mjml-image src="..." href="..." custom-attr="edit-link,hide-link" />

<!-- or (is this possible?) -->
<mjml-image src="..." href="..." custom-attr="edit-link" custom-attr="hide-link" />
<!-- Shorthand version -->
<mjml-image src="..." href="..." custom-attr="table > tr > td a;mc:edit;" />

but I really dislike that we are creating a new DSL (the tr td a;data-tracking-id;24 is non-transparent).

It's not really a new DSL it's a simple CSV... We're not yet in the implementation anyway so this can be tweak later.

But I totally disagree with you HTML/XML has a very flexible attribute system, it limits us here because of the 1 to N binding.

Even if I really like the extension analogy from Swift, other solutions add extra verbosity and must rely on reading mj-head to read/access a lot of informations. I don't feel that it will be easier to debug in any way ?

However, it can work nicely with attribute validation given the fact that we'll have to pre-parse the document to validate new "custom" attribute.

If you want to add multiple attributes you can just group & indent them nicely :

<mj-text 
  attach="
    td;data-article;1;
    div;contenteditable;true;
    table;data-useless;true
  "
/>

You have every piece of informations here to understand what you'll have on the final output, and it will be in the same order : [css selector];[attr_name];[attr_value]. It can be easily debugged on attribute validation when it fails to parse (too much / too few args) or css selector is wrong.

I totally agree with iRyusa on this point, one of the reasons is that it will be much cleaner in the code. These attributes needs to be added when the component is rendered, so if we can handle this directly in the component and don't have to use data from the mj-head it will avoid passing data all over the place ;)

@iRyusa It's not really a new DSL it's a simple CSV... - with all due respect, it's a DSL. It has rules about what characters it will accept, how will it escape ; or ", how many fields are a valid and invalid syntax. It's a DSL, imo an unnecessary one, although I can understand that it might make sense from a 'what is easy to implement right now in current code' point of view.

HTML/XML has a solution for multiple sets of properties:

<!-- define new attributes -->
<mj-attributes>
    <mj-class name="mailchimp_button" ...>
        <mj-class-attribute id="edit-link" selector="table > tr > td a" name="mc:edit" value="" />
        <mj-class-attribute id="cancel-link" selector="table > tr > td a" name="mc:cancel" value="" />
    </mj-class>
</mj-attributes>


<!-- use them -->
<mj-button mj-class="mailchimp_button" edit-link="..." cancel-link="...">Click here</mj-button>

I also really dislike the idea of having to repeat the selector - the selector for eg. a link inside a button is a same for all instances of a button, why should I be required to copy and paste it flawlessly into every place where a button is? That's why I chose to put it inside a <mj-attributes> in the above example, it should exist exactly once in a document.

Then any css property is a DSL from your standpoint ¯\_(ツ)_/¯

The debate isn't really on how easy it is to implement a solution, we rewrote MJML from the ground in MJML 3 => 4 from React to nothing.

It's more how any (new or confirmed in MJML) developer will understand how align is not a custom attribute and why cancel-link is. From your implementation, there's no way to know that directly. You have to refer to mj-head, and check if the tag is actually a custom one or a legitimate MJML attribute, and worst case scenario where you have many include with mj-head inside find the right one (this point is still valid for mj-class but at least you know what you're looking for).

I also really dislike the idea of having to repeat the selector - the selector for eg. a link inside a button is a same for all instances of a button, why should I be required to copy and paste it flawlessly into every place where a button is?

This one is a legitimate concern, and I feel my approach doesn't have any way to fix that nicely. Relying on mj-class will still have the same value for an attached attribute or it would need some kind of selector alias and that's not really great.

I would suggest the following inside any mj- component:

<mj-image align="left" padding="0" src="https://somesourceimage.com">
  <mj-merge-result>
    <!-- pulled from the expected output -->
    <table>
      <tbody>
        <tr>
          <td> <img mc:flag="true"> </td>
        </tr>
      </tbody>
    </table>
  </mj-merge-result>
<mj-image>

I have found my self often in a strange place, where I want the functionality that mjml provides out of the box, but there is something that doesn't quite work. I end up using some sort of hack on top of mj-raw or mj-text and creating the html manually. This means for those elements I lose the capability to rely on mjml.

Since others have created a process to merge what they need into the result, it seems like it would be better (and extensible to any other case) to allow a custom html to be applied to the result. I would merge the output with the mj-merge-result html to get the final version. Sure there are some additional flags which could help with some complexities like:

  • merge-attribute-tags="true"
  • prefer-mjml-output="false"

etc...

While you could argue this requires anyone playing around with these tags to have to know the output, I would argue that they would need to anyway if they were planning on changing it. But this way makes the result more extensible and allows for an improvement over mj-raw where complete usage of html is necessary.

Then it won't work with any content tag because we don't want parse content to mess with it ?

Plus technically I don't really get how we'll be able to "merge" html produced like that. You won't be able to reuse any given modification too.

Looks like @cossssmin project https://github.com/cossssmin/alter.email has a similar feature now. It simply iterate over selector & apply them with cheerio.

May be we can offer a minimalist version for now , & selectors can be tweak with css-class for accessibility. (name to discuss)

<mj-custom-attributes>
  <mj-selector path="div.mj-column-per-100">
    <mj-attribute name="data-id">42</mj-attribute>
    <mj-attribute name="data-column">sexy feature</mj-attribute>
  </mj-selector>
  <mj-selector path="div.mj-column-per-50">
    <mj-attribute name="data-id">21</mj-attribute>
  </mj-selector>
</mj-custom-attributes>

Advantages : no breaking change for MJML components ( so no need MJML 5 with heavy migrations for custom components), can be done quite easily (we just need to introduce a way to inject post render hooks in mj-head ) XML friendly (making @tkafka happy ;D), can be disabled quite easily (remove the dep).

Drawbacks : Not deeply integrated into mjml-core, harder to find what will be altered at the end, values can't be adjusted for a single node, so a lot of duplications and can't be factored

Hi there is there any news? i tried last version stil not abble to use mailchimp tags :(

Not yet, seems like the last version would be a great compromise, we'll talk about this with @ngarnier next week to see if we can push this in next "big" release

We also would need something like a unique html id.

And for example the id at an mj-image

<mj-image id="xyz" src="https://mydomain.com/picture.png" href="https://superdomain.com" />

where should be the id? and how should the code looks like?

<a href="https://superdomain.com">
   <img id="xyz"  src="https://mydomain.com/picture.png"/>
</a>

or should it be like this?

<a id="xyz" href="https://superdomain.com">
    <img id="xyz"  src="https://mydomain.com/picture.png"/>
</a>

or would it make more sense to have something like:

<mj-image image-id="xyz-image" src="https://mydomain.com/picture.png" href="https://superdomain.com" href-id="xyz-link"/>

to get something like:

<a id="xyz-link" href="https://superdomain.com">
  <img id="xyz-image"  src="https://mydomain.com/picture.png"/>
</a>

Should I open an extra issue, as the HTML ID is W3C Standard, so I don't see it as a custom ? Or is it also covered with this one?
We would need this for example for having automatic tests to check if everything we expect to be in the rendering or not

You're describing exactly the issue with those ambiguous HTML attribute that could be placed in multiple places to make everyone happy. Multiplying attributes would bloat the attribute list and support, so maybe custom attribute is the right name for that.

Proposal of https://github.com/mjmlio/mjml/issues/200#issuecomment-536611411 totally solve your issue as you can just put an id wherever you want

that would be okayish i guess.
Is there any plan to get this in master soon?

Hi @everyone-on-this-thread, following this discussion we finally released a feature allowing to add any attribute to the generated html. You can install the beta with the next tag, i.e. npm i mjml@next
Here is the documentation for this : https://github.com/mjmlio/mjml/blob/master/packages/mjml-head-html-attributes/README.md

Hi @everyone-on-this-thread, following this discussion we finally released a feature allowing to add any attribute to the generated html. You can install the beta with the next tag, i.e. npm i mjml@next
Here is the documentation for this : https://github.com/mjmlio/mjml/blob/master/packages/mjml-head-html-attributes/README.md

Is there any way to get this beta version to work in the MJML app? I'm new to all of this and been pulling my hair out the last 3 hours trying to get NPM to give me a workable version. Theres almost no new user guides on getting this all setup, it just assumes I am a competent (lol) user.

This won't work with Marketo Container and Module. I know no one uses Marketo, just putting it out there.

Maybe you can explain why it won't work ?

Of course, so Marketo relies on using Containers on table or td elements. Because nesting tables is very common in HTML email, it makes it really hard to target.

Also to use Marketo's Container and Module, the Module has to be the immediate children of the Container. E.g.

<table class="mktoContainer">
  <tr class="mktoModule"><td>1</td></tr>
  <tr class="mktoModule"><td>2</td></tr>
  <tr class="mktoModule"><td>3</td></tr>
</table>

Otherwise it won't work.

Docs: https://docs.marketo.com/display/public/DOCS/Email+Template+Syntax#EmailTemplateSyntax-Variables

For things like table you can just use regular css class on a mj-table et apply class & stuff inside it properly?

<mj-table  css-class="mktoContainer">
    <tr class="mktoModule"><td>1</td></tr>
  <tr class="mktoModule"><td>2</td></tr>
  <tr class="mktoModule"><td>3</td></tr>
</mj-table>

You can also use mj-text for that purpose

<mj-text>
  <table class="mktoContainer">
    <tr class="mktoModule"><td>1</td></tr>
    <tr class="mktoModule"><td>2</td></tr>
    <tr class="mktoModule"><td>3</td></tr>
  </table>
</mj-text>

Here the provided solution allow you to apply any attribute to any tag given a proper css selector ?

Oh sorry I forgot to mention that in order for all of the Module and Container to work, you'll need the attribute id and mktoname in each associated elements as well. E.g.

<tr class="mktoModule" id="section-1" mktoName="Main Section 1"></tr>

Also in each module we usually have stuff like mj-column to build out the entire template.

I don't get what you can't do with this mj html attributes then, if you're inside a mj table/text you're able to add any custom attributes directly, and if you need to target a deep html element of MJML mj-html-attributes will help you to do so

Hi @everyone-on-this-thread, following this discussion we finally released a feature allowing to add any attribute to the generated html. You can install the beta with the next tag, i.e. npm i mjml@next
Here is the documentation for this : https://github.com/mjmlio/mjml/blob/master/packages/mjml-head-html-attributes/README.md

Hi!

As this is already released at 2020-09-18, is there any misterious reason this isn't on documentation yet?

We're moving from our slow manual deploy process to a new one with github action.

Links on mjml.io website aren't updated yet but you can find it here https://documentation.mjml.io/#mj-html-attributes

Actually the links are updated on mjml.io, so if you access the documentation from the website you will see the updated one (https://documentation.mjml.io/). However if you access via the old URL (https://mjml.io/documentation/), it might be outdated. Maybe we should set a redirect @iRyusa @kmcb777?

The big "Documentation" button redirects to the old one and footer links too 😄
But yep we can add a permanent redirect (would be good for SEO anyway)

Hello,

Looking to get some help on the following, I can't seem to spot what triggers those errors. Using VSCode with the MJML extension and confirmed I am on 4.8.1 with no other references in package-lock.
The html attributes are confirmed not present in the HTML output.

I've reviewed this thread, the live example and the documentation but to no avail. Thanks for the help!

<mjml>
  <mj-head>
    <mj-html-attributes>
      <mj-selector path=".module-1-h1 div">
        <mj-html-attribute name="mc:edit">module-1-h1</mj-html-attribute>
      </mj-selector>
      <mj-selector path=".module-1-subhead div">
        <mj-html-attribute name="mc:edit">module-1-subhead</mj-html-attribute>
      </mj-selector>
      <mj-selector path=".module-1-img div">
        <mj-html-attribute name="mc:edit">module-1-img</mj-html-attribute>
      </mj-selector>
      <mj-selector path=".module-1-caption div">
        <mj-html-attribute name="mc:edit">module-1-caption</mj-html-attribute>
      </mj-selector>
      <mj-selector path=".module-1-h2 div">
        <mj-html-attribute name="mc:edit">module-1-h2</mj-html-attribute>
      </mj-selector>
      <mj-selector path=".module-1-body div">
        <mj-html-attribute name="mc:edit">module-1-body</mj-html-attribute>
      </mj-selector>
      <mj-selector path=".module-1-link div">
        <mj-html-attribute name="mc:edit">module-1-link</mj-html-attribute>
     </mj-selector>
   </mj-html-attributes>
  </mj-head>

Returns the following errors:
image

If you're still using the old VS-Code extension, this would probably happen. The MJML team forked that one; you'd do well to convert, if you haven't. Then check again.
Recent discussion: https://mjml.slack.com/archives/C12HESC2G/p1609770450379800
Hope that takes care of it.

@GarryFlemings thanks much that did it!

When I try to use the api.mjml.io I get Element mj-html-attributes doesn't exist or is not registered. Isnt the api updated according to the documentation?

I think the API is still on 4.7, that's why

I think the API is still on 4.7, that's why

Would be great if someone could click the update button :)

Updating the API require a bit of time to ensure there's no package with open vulnerabilities. If you're not really happy with the service you're free to self host updated version of it on any PaaS.

const express = require('express');
const app = express();
const mjml2html = require('mjml');

app.post('/render', function(req, res) {
  res.send(mjml2html(req.body));
});

app.listen(port)
Was this page helpful?
0 / 5 - 0 ratings