If you want to dive right in, check out the Markdown Starter.
Project setup
Scaffold a new project using the Markdown Starter:./markdown-project, and select the Default Starter.
Choose Yes when prompted to Install dependencies.
Once it finishes installing dependencies, open the project folder in your favorite code editor.
Structure
We’ll be using thecontent folder to store our Markdown files:
You can remove the
emails directory, we won’t need it.content/newsletter-1.md and add some markdown to it:
newsletter-1.md
Layout
Since we just want to write Markdown and not have to deal with any tables and such, we need to updatelayouts/main.html to contain the entire HTML boilerplate.
Replace its contents with the following:
layouts/main.html
Dependencies
We’ll need a couple of extra dependencies to parse the Markdown files:front-matterto be able to use Front Matter in our Markdown filesmarkdown-it-attrsto be able to add Tailwind CSS classes right in Markdown
config.js
Since we’re not using the default setup anymore, we need to tell Maizzle where to look for ‘templates’ to compile. Updatebuild.templates to use .md files from the content folder:
config.js
Compile Markdown
If you runnpm run build now, you’ll notice the files output to build_production only include the raw, unparsed content of your Markdown files: they were not compiled to HTML, neither did they use our main.html layout.
Maizzle doesn’t know what layout to use or that the content of our .md files is Markdown that needs parsing, so we need to instruct it to do that.
We can use the beforeRender event for this:
config.js
- We’re hooking into the
beforeRenderevent to alter the HTML before it’s compiled. - We use
front-matterto extract the Markdown content from the file into abodyvariable. This ensures that we only parse Markdown content, and not the Front Matter too. - We’re returning a string that includes the contents of the
bodyproperty wrapped in<md>tags, so Maizzle can parse them as Markdown. See the Markdown documentation for more info on this tag. Finally, the<x-main>tag tells Maizzle to use ourmain.htmllayout.
npm run build again and you’ll see that the files in the build_production folder are now compiled to HTML using our main.html layout.
Styling
Let’s create acss/markdown.css file so we can add some global styles for our Markdown content:
css/markdown.css
<style> tag:
layouts/main.html
npm run build again and you’ll see that the styles are now applied:
build_production/newsletter-1.html
Tailwind CSS
We can also use Tailwind CSS classes directly in our Markdown files. To do this, we’ll use themarkdown-it-attrs plugin, which allows us to add attributes like class names to elements right when writing Markdown.
Update config.js to have Maizzle use the plugin:
config.js
content/newsletter-1.md
build_production/newsletter-1.html
@tailwindcss/typography
Although it’s the obvious choice for styling Markdown content with Tailwind, we don’t recommend using @tailwindcss/typography for Markdown emails. The plugin is great for the web, but it contains complex CSS selectors that are not fully supported by most email clients, and cannot be properly inlined either. Feel free to experiment with it, but consider yourself warned.Syntax highlighting
You can use syntax highlighters like Shiki or Prism to add syntax highlighting to fenced code blocks in your markdown. For example, here’s how you’d use Shiki. First, install the library:highlight method for markdown-it. Add it in the beforeCreate event so that the highlighter is retrieved once, before templates are compiled:
config.js
Expressions
You can use expressions in Markdown files just as you would in any Maizzle template:content/newsletter-1.md
Components
You can also import Maizzle components in your Markdown files. For example, let’s create an<x-alert> component:
components/alert.html
attributes attribute - this indicates that any attributes passed to the component should be added to this element, instead of the root element.
We can use it like this:
content/newsletter-1.md
Markdown in components
To use Markdown inside a component, add an empty line before and after the content that you pass inside:content/newsletter-1.md
markdown-it that would result in <pre> tags being added to the rendered HTML, simply don’t indent the closing tags after <yield />. A bit of a workaround, but it works:
components/alert.html
prettify transformer to remove the indentation:
config.js
Custom layouts
You may need to use different designs for your newsletters. We can use Front Matter to do this, by defining a custom layout name for each Markdown file to use. Go ahead and createlayouts/secondary.html based on main.html.
For the purpose of this tutorial, we’ll just change the body background color to differentiate it from the main.html layout: replace both occurrences of bg-slate-100 with bg-indigo-200.
Next, update the beforeRender event in config.js to use the layout name from Front Matter:
config.js
content/newsletter-1.md
build_production/newsletter-1.html now has an indigo background color, which means it’s using our custom layout.
Outlook note
Your markdown may include retina-sized images that will very likely be larger in natural size than the 600px width of the layout. By default, compiling Markdown to HTML will not add awidth attribute to images.
While this is fine in browsers and modern email clients because you can control it through CSS, it will be an issue in Outlook for Windows: not specifying the width of an image will render it at its natural size, blowing up the layout in case of retina images.
To fix this, we can use markdown-it-attrs to manually add our image width in Markdown:
content/newsletter-1.md
) and the opening { where we specify the attribute. This ensures the attribute is added to the img tag, and not the p tag wrapping it.
Resources
- GitHub repository for this guide
- For the new components syntax, see the Maizzle 4.4.0-beta release notes
- Docs for Markdown in Maizzle