Introducing mjmx: a custom JSX runtime for mjml

·

In my opinion, one of the best things that happened because of React, is JSX. I know many people seem to hate on JSX, but I like it. With JSX, or more specifically TSX, one can write typesafe html, instead of relaying on libraries like handlebars, which is a great library, but it keeps your code and your variables separated. So every change in variables needs to be synced to the view-model, or worse, risk in runtime errors / blank values.

Recently, I’ve been doing some server-side rendering, and was using @kitajs/html as HTML JSX runtime. @kitajs/html is great, because it does not bring react or react-dom with it. And when I got to emails, I decided to try react-email and mjml-react. But I was disappointed in both.

First of all, I like mjml. It’s a great syntax, and it’s battle tested. react-email seems to not use mjml, but instead re-implement email rendering themselves. Now, react-email is a product by Resend, and the guys at Resend are doing email sending, so I bet they know how to render emails properly. Despite this, there is a second issue: I don’t like React, and I don’t want to bring react and react-dom just to render a couple of emails.

So I decided to try to write a custom JSX runtime for mjml. And that’s how @mjmx/core was born: mjmx Github.

It’s a custom JSX runtime that has no dependency on react or react-dom. It implements the minimum needed runtime to support all the mjml tags, as well as the allowed HTML tags. And with it, writing mjml becomes a breeze:

const Email = ({ name }: { name: string }) => (
  <mjml>
    <mj-body>
      <mj-section>
        <mj-column>
          <mj-text font-size="20px" color="#333">
            Hello {name}!
          </mj-text>
          <mj-button href="https://example.com">Click me</mj-button>
        </mj-column>
      </mj-section>
    </mj-body>
  </mjml>
);

const { html, errors } = render(<Email name="World" />);

Under the hood, render is just a proxy to mjml2html from the mjml library. This means that mjml compilation happens with each email you render. I would like to outsource the mjml compilation into a build / transpile step, but with the current approach it is not possible, unless you decide to re-implement email rendering yourself.

I hope you will find this library useful. Don’t forget to star it on GitHub, and feel free to reach out to me for questions, or open an issue / PR for suggestions and improvements.

Share this:

Published by

Dmitry Kudryavtsev

Dmitry Kudryavtsev

Engineering Leadership, Senior Software Engineer / Tech Entrepreneur

With more than 14 years of professional experience in tech, Dmitry is a generalist software engineer with a strong passion to writing code and writing about code.


Technical Writing for Software Engineers - Book Cover

Recently, I released a new book called Technical Writing for Software Engineers - A Handbook. It’s a short handbook about how to improve your technical writing.

The book contains my experience and mistakes I made, together with examples of different technical documents you will have to write during your career. If you believe it might help you, consider purchasing it to support my work and this blog.

Get it on Gumroad or Leanpub


From Applicant to Employee - Book Cover

Were you affected by the recent lay-offs in tech? Are you looking for a new workplace? Do you want to get into tech?

Consider getting my and my wife’s recent book From Applicant to Employee - Your blueprint for landing a job in tech. It contains our combined knowledge on the interviewing process in small, and big tech companies. Together with tips and tricks on how to prepare for your interview, befriend your recruiter, and find a good match between you and potential employer.

Get it on Gumroad or LeanPub