Features
Zero React Dependency
Pure JSX runtime with its own AST. No react or react-dom needed.
Full TypeScript Support
Template literal types for CSS values, colors, percentages. Autocomplete that works.
All MJML Components
40+ components with strictly typed attributes. Every MJML tag, fully supported.
Component Composition
Reusable email components with PropsWithChildren, fragments, and conditionals.
Two Render Modes
render() for HTML output,
serialize() for MJML strings.
Lightweight & Fast
Pure string manipulation. No virtual DOM, no reconciler.
Code Examples
import { render } from '@mjmx/core'; 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" />);
import { render, type PropsWithChildren } from '@mjmx/core'; const Card = ({ children, title }: PropsWithChildren<{ title: string }>) => ( <mj-section> <mj-column> <mj-text font-weight="bold">{title}</mj-text> {children} </mj-column> </mj-section> ); const Header = () => ( <mj-section background-color="#2c3e50"> <mj-column> <mj-text color="#fff" font-size="24px">My App</mj-text> </mj-column> </mj-section> ); const WelcomeEmail = ({ name }: { name: string }) => ( <mjml> <mj-body> <Header /> <Card title="Welcome!"> <mj-text>Hello {name}, thanks for joining.</mj-text> </Card> </mj-body> </mjml> );
mjmx (JSX)
const OrderEmail = ({ items }: Props) => ( <mjml> <mj-body> <mj-section> {items.map(item => ( <mj-column> <mj-text>{item.name}</mj-text> <mj-text>{item.price}</mj-text> </mj-column> ))} </mj-section> </mj-body> </mjml> );
MJML + Handlebars
<mjml> <mj-body> <mj-section> {{#each items}} <mj-column> <mj-text>{{this.name}}</mj-text> <mj-text>{{this.price}}</mj-text> </mj-column> {{/each}} </mj-section> </mj-body> </mjml> <!-- No type safety --> <!-- No autocomplete --> <!-- No component reuse -->
Getting Started
1
Install
Add mjmx and mjml to your project.
$ npm install @mjmx/core mjml
2
Configure TypeScript
Set the JSX transform in your tsconfig.json.
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@mjmx/core"
}
}
Or use the pragma:
/** @jsxImportSource @mjmx/core */
3
Write Your First Email
Create a component and render it to HTML.
import { render } from '@mjmx/core'; const { html } = render( <mjml> <mj-body> <mj-section> <mj-column> <mj-text>Hello World!</mj-text> </mj-column> </mj-section> </mj-body> </mjml> );