Built around components, MJML comes with a library of standard tags. Some of those tags can be very high-level (such as mj-carousel which abstracts the complexity of having a functional carousel in an email, with all necessary fallbacks), while others are more basic (mj-text for example).
However, it is also possible to create your own components. This can be especially useful if you need to reuse a specific layout across your templates. With MJML 4, we made the creation of a custom component even simpler. Let’s create our first custom component together.
Installing the boilerplate
To get you started smoothly, we created a boilerplate which will relieve you from having to do any manual setup.
First, open a terminal and download the boilerplate with git:
git clone https://github.com/mjmlio/mjml-component-boilerplate.git
Then, go to the folder where you downloaded it:
Now, install it with NPM:
Finally, run it with Gulp:
You just rendered your first custom components! Open the
index.html file which was created in the same repository to see the 3 custom components we’ll study today.
Understanding the structure of the boilerplate
Now that we installed and used the boilerplate, let’s look at what’s inside.
index.mjml: this file is the MJML file where we will use our custom components
/components: this folder contains the custom components we will use and that we are referring to in
/lib: this folder will contain the compiled output of the components located in
/components. You should not edit any file in this folder.
gulpfile.babel.js: this file is responsible for building each component and registering them in MJML, so that they can be used in
Rendering your first custom component
Before looking at the components themselves, let’s look at the file
gulpfile.babel.js to understand how to render our own components. In the first 13 lines, we’re importing all the dependencies needed (such as MJML but also each component located in
/components), while from lines 14 to 16, we’re registering each component thanks to the
registerComponent method of
mjml-core (importing them only is not enough).
Let’s look at the rest of the file and start with the
First, we fetch each file located in the
/components folder with a
compile them with babel and write the compiled files in
Then, now that the components are built, we render the
index.mjml file to HTML and write the output in
Finally, we simply declare two gulp tasks, that are available with
gulp *task* (
*task* being the actual name of the task as described below).
build: this task will simply run the
compilefunction when executed
watch: this task will watch any change made to the components located in
/componentsas well as the
index.mjmlfile and automatically run the compile function when changes are detected. Pretty useful to build as you code your own component!
You now know how the
gulp build command you ran earlier works!
Creating your own component
Let’s now look at the custom components located in
/components and start with the simplest one:
Let’s start with a component that simply outputs a text wrapped inside 2 star icons wrapped inside a HTML
<div>. You’ll discover how to use and pass attributes in your own components, as well as how to make them render the output you want.
First, we are registering the dependencies of our components, to state where it can be used. On line 2 and 3, we define that
mj-basic-component can be used inside
mj-column. On line 4, we define that no other MJML component can be used inside it.
Then, we use a few properties & methods inherited from
BodyComponent to define our component:
endingTag: specifies if this tag can use other MJML tags as its children
allowedAttributes: tells the validator what attributes can be used on it
defaultAttributes: sets a default value for its attributes
render(): this is where the magic happens, as this is the place where we define what will be the HTML output for our component
For more details about each property and method, please read the comments in the file.
You can also notice in the
render method that we’re passing the styles to our HTML tags by using the
getStyles methods together.
Here is the important difference between the two:
htmlAttributes: this method adds to the rendered output the attributes that are passed to it as an argument, following the syntax
attribute="value". While this is valid for HTML & MJML attributes, it is not valid to use CSS styles on our HTML elements (as they should be inside a
getStyles: this method was created precisely for the reason mentioned above. You can use it to format the attributes you pass to it, following the syntax
style="attribute:value;", instead of
this.getAttribute also handles automatically the value of an attribute, to use either the value set when using your component or its default value fallback (set in
defaultAttributes) if no value was passed.
Finally, we use
this.getContent inside the inner
span element to get the content of your component (what’s in between its opening and closing tags), and print it within its output.
This component is a bit more complex in terms of structure, as it renders a section composed of 2 columns, each column containing respectively an image and a text. The best part of this component is that you’ll discover your custom components can also reuse existing MJML components!
First, we created a method called
renderImage that renders a
mj-column with a 50% width (set in
defaultAttributes), with a
mj-image in it. You’ll notice we use the methods
getAttribute that we mentioned above in our basic example.
Similarly, we created a
renderText method that does the same, except it uses a
mj-text instead of
Now that we have those two column blocks, we just have to assemble them like Lego blocks inside a
mj-section, which we’re doing in the final
You can notice on the line two of this gist that we control the order of the column by reordering the two Image and Text block of our components, based on the
This component uses the same concepts as
MjImageText and introduces two new methods to control the styles outputted in the
head of the HTML output.
headStylemethod: this function adds the generic head style needed for
<head>of the HTML file outputted. In this case, it defines some general CSS styles (such as a border), as well as its responsive behaviour with a media query. As it’s generic, the style set in that function will be added to the head of the HTML file only once and used by all the instances of
mj-layoutin the file.
componentHeadStylemethod: this function adds the head style specific to each instance of this component to the
<head>of the HTML file. As it is different for each instance of the tag, it will be outputted as many times as the component is used in our MJML file.
Here is what we’re doing:
- randomly generate an ID for each instance of the component (line 3)
- target each instance of the component thanks to their ID inside the mobile media query (line 10 & 11)
- set the width of each instance based on its ID (line 12)
Try now to add several
mj-layout in your
index.mjml and resize it. You’ll notice each instance has a different width on mobile!
And voilà, you know how to create your own custom components. To practice what you have just learned, try to fiddle with those components. For example, why not try to control the
font-size of the
mj-basic-component via an attribute?
If you create new ones in
/components, remember to:
- Import and register them in
- Use them in