My thoughts on Mithril.js


My thoughts on Mithril.js

Mitril.js is a client-side JavaScript framework (similar to React, Vue, Svelte, etc.)

My current go-to client-side framework is Svelte - which is amazing. The only real downside is that it cannot be used without build-tools.

So when I noticed that Mithril.js can be used without any build-tools (plain vanilla JavaScript) AND it has a tiny runtime (10 kB) AND it has real components - I was intrigued.

Having (real) components, sets it apart from other no-build / small runtime frameworks (like Alpine.js and Vue-Petite), because this allows for the creation of advanced full-size SPAs.

Basically, Mithril.js covers both scenarios - "progressive enhancement" (like Alpine.js and Vue-Petite) and full-size SPA (like React, Vue, Svelte).

Could this be the one? The single tool for everything? The holy grail?

So I played around with Mithil.js over the weekend, to see what it was like.

With Mithril.js, you generate HTML using a hyperscript dialect like this:

m("div", {style:"color:red"},
  m("a", {href:"/page2"}, "click here"))

which generates

<div style="color:red">
  <a href="/page2">click here</a>

Alternatively, you can use JSX syntax (like with React), but then you need build-tools.

Another option is using the htm library to generate the hyperscript - which would allow the use of JavaScript template literals for a development style closer to JSX or the HTML templates used with Vue / Svelte. The problem with this is that the templates would be re-compiled (by htm) on every single interaction with the app - which I imagine would seriously slow things down.

So the way I see it, the optimal way to use Mithril.js (without build tools) is to write the hyperscript style code by hand - which actually isn't too difficult once you get used to it. The biggest problem is keeping track of closing parentheses/brackets with deeply nested elements.

Reactivity / UI updates

Unlike the major frameworks (Reach, Vue, Svelte, etc.) Mithril.js does not update the UI in response to changes in application state / variables.

Instead, it updates the UI after each UI event has been handled (or whenever you tell it to by calling m.redraw()).

On each update it re-renders everything to a new virtual DOM, then diffs this to the previous version, and finally updates the real DOM with the differences.

This works surprisingly well. Dynamic and automatic UI updates - without any kind of state tracking. Very nice!

Test project

I recently created a small SPA here: - an in-browser tool to generate DMARC-records - an e-mail security thing.

So to try out Mithril.js, I re-created the same SPA using Mithril.js.

The following is based on my experiences doing that.

Things that I really like

Things that really should be removed


Mithril.js has some really nice and unique features.

But, while the hyperscript syntax is doable for small widgets, I wouldn't want to use it in larger projects.

I just don't think that the hyperscript syntax is as readable as for example Vue / Svelte templates (standard HTML with as few additions).

And keeping track of those closing parentheses/brackets with deeply nested elements, just drove me nuts.

As the JSX docs put it (about something else, but with the same issue):

Unfortunately, the balanced braces do not give great syntactic hints for where an element starts and ends in large trees. Balanced named tags is a critical syntactic feature of the XML-style notation.

So to use Mithril.js, I would probably need JSX, which requires build tools. And if I have to use build tools anyway, then I still prefer Svelte...

Jesper Høy's
Dev Blog

  • Home (blog posts)
  • About me and this website
  • My developer tech stack
  • My favorite software
  • My favorite online services
  • Cool stuff
  • My side projects
  • Referral codes
  • Our wonderful ice horses