A Beginner's Attempt at Mithril.js
Tags: webdev, beginners, javascript, tutorial
Published: 2017-12-12 09:18:14

---
title: A Beginner's Attempt at Mithril.js
published: true
description: Let's recreate a color button using Mithril.js!
tags: webdev, beginners, javascript, tutorial
---

I started teaching myself web development about half a year ago, and one of the first "from scratch" front-end projects I created was a color button. Basically, type in a valid color name (most of which you can find [here](https://www.w3schools.com/colors/colors_names.asp)) or hex value, and after clicking the button, its color would change to the one that was inputted. 

I came up with this idea as an exercise for using event listeners in JavaScript because I was having trouble with them at the time, and so I focused on using just plain JavaScript when creating it. Here's the result:

{% codepen https://codepen.io/andrew_chou/pen/mMNerL %}

It's pretty simple and I'm sure that there are more efficient ways to do this using plain JS (NOTE: I haven't tried to change it since I finished it). 

As a beginner, it's easy to be overwhelmed by all of the front-end frameworks that exist. I wanted to "level up" and try something unfamiliar but not too unfamiliar. I was looking for something that would introduce more advanced concepts, but without straying too far from what I already understood. Also, I'm a complete sucker for minimalist frameworks and libraries, so that was a consideration when looking for something to try as well.

And so I found [Mithril.js](https://mithril.js.org). It's known to be extremely minimal (<8kb gzip!) and it has a simple API that can be used similarly to [React](https://reactjs.org/). Its documentation definitely contains more content about how to use Mithril than it does about its actual API, and so I highly recommend it to beginners.

So for the rest of the post, I'm basically going to rewrite the color button I made earlier - using Mithril. Feel free to follow along using [CodePen](https://codepen.io) or whichever sandbox tool you prefer!


### Step 1: Create Some Components

If you're familiar with React, then you'll understand what I mean when I say that we can view each of the elements for this application as a *component*. The input, the color button (AKA the big button), and the reset button are each a component that, when put together, make up the content of the page. Components in Mithril are basically just objects with a `view` property, which is a function that returns some markup node(s). For example, let's start by creating a component for the input:

~~~javascript
const InputComponent = {
  view: function() {
    return m("div", "This is the input container")
  }
};

// The view function is essentially returning this HTML element:

// <div>This is the input container</div>

~~~ 

What the function in `view` is returning is what Mithril refers to as a *vnode*, which is essentially an HTML element. The `m()` function is a hyperscript function that allows any HTML structure to be written in JavaScript syntax - so in this case, the first argument indicates the type of element it is (a `div`), and the second argument is the text that's contained in the element. 

Right now, the input component only contains the container element that I used for styling purposes. To add the necessary elements, we can nest elements into this `div` like so:

~~~javascript
const InputComponent = {
  view: function() {
    return m("div", { id: "input" }, [
    m("label", "input color: "),
    m("input", {
        id: "color-input",
        type: "text",
        onkeydown: submit,
        autofocus: "autofocus"
      })
    ]);
  }
};

// Now the view function renders the following HTML:
/*
<div id="input">
    <label>input color: </label>
    <input id="color-input" type="text" onKeyDown="submit" autofocus="autofocus">
</div>
*/

~~~

It may look complicated at first glance, so I'll explain what I added:
  
1. We notice that now the second argument of the `m()` function is an object containing different properties. In Mithril, we can define the attributes of the HTML tag here. So my container `div` element now has `id="input"` when rendered. The same goes for the `input` element that's defined.  

2. The last argument of the `div` element is an array of other elements. This is how we can nest elements in Mithril. So now our `div` element contains a `label` element and an `input` element.  

3. It's important to notice that the `input` element has the attribute `onkeydown: submit`. Right now, `submit` is a function that we haven't defined, but due to Mithril's [autoredraw system](https://mithril.js.org/autoredraw.html), you don't want to set this attribute to `submit()` i.e. calling the function.  


Now we have the whole input component done. Let's quickly create the color button and the reset button:  

```javascript
const ColorButtonComponent = {
  view: function(vnode) {
    return m("div", { id: "color" }, 
        m("button", {
            id: "color-btn",
            style: `background-color: ${vnode.attrs.color.background}`,
            onclick: submit
          })
        );
  }    
};


const ResetButtonComponent = {
  view: function(vnode) {
    return m("div", { id: "reset" },
        m("button", {
          id: "reset-btn",
          style: `border-color: ${vnode.attrs.color.border}`,
          onclick: submit
          },
          "reset"
          )
        );
  }
};
```

A few things to note here:  

1. The `view` function for each component now has a `vnode` argument. We'll see how this is used when we render our components together.  

2. Each of these buttons contain an `onclick` attribute, instead of an `onkeydown` attribute like we saw with the input component, but they still invoke the same `submit` function. 

3. The `style` attribute references some property from the `vnode` argument in the   `view` function. This is a way of accessing data. In this case, we're referencing some `vnode` to figure out what color the color button's background and the reset button's border should turn into. 


### Step 2: Add in the State Variable and Necessary Functions

So we finally created our components! But we still need to define some functions that will help us to actually change the colors:

~~~javascript
// This acts as our global state for the component color
// Our components will access this whenever the buttons are clicked or the correct keys are pressed.
let State = {
  background: "#ffffff",
  border: "#000000",
  defaultBackground: "#ffffff",
  defaultBorder: "#000000"
};


function changeColor(val) {
  State.background = State.border = val;
}


function resetToDefault(element) {
  State.background = State.defaultBackground;
  State.border = State.defaultBorder;
  element.value = "";
}


// This is the submit function that we saw in the components before
function submit(event) {
  let inputElement = document.getElementById("color-input");
  let currentValue = inputElement.value;

  switch (event.type) {
    case "keydown":
      switch (event.keyCode) {

        // If the Enter key is pressed...
        case 13:
          changeColor(currentValue);
          break;

        // If the Escape key is pressed...
        case 27:
          resetToDefault(inputElement);
      }
      break;

    case "click":
      if (event.target.id.includes("reset")) {
        resetToDefault(inputElement);
      } else {
        changeColor(currentValue);
      }
      break;
  }
}

~~~

Once again, looks like we did a lot. Here's the rundown:  

1. We created an object `State` that acts as the global state for our app. To be quite honest, I'm not sure if this is the best way to do that, but it works for something small like this. The `background` and `border` properties of `State` are accessed by the components, as we'll see in a little bit.  

2. We created the `submit` function that we saw earlier in our components. We also created two helper functions, `changeColor` and `resetToDefault`. The `submit` function listens for an event i.e. a mouse click or a key press, and invokes the helper functions, which change the `background` and `border` properties of `State` depending on the event. This is then communicated to the elements as it occurs (more on this soon).  

 

### Step 3: Put It All Together

So now we have all of the components and the necessary variables and functions, but how do we actually make it so that we have a working app on our screen? The solution to this is the `m.mount` method in Mithril. This takes a component and "attaches" it to some part of the DOM, whether it's an HTML element or some other part of the window. In this case, we're going to create a component *that contains all of the components we made*, and then attach it to `document.body`:

~~~javascript
const App = {
  view: function() {
    return m("div",
      { id: "flex-container" },
      m(inputComponent),
      m(ColorButtonComponent, { color: State }),
      m(ResetButtonComponent, { color: State })
    );
  }
};

m.mount(document.body, App);
~~~

This may be a little confusing at first. To put it simply, our `App` component is creating elements based on the components we defined earlier. In other words, `App` is a component that contains components. What's rendered from these elements depends on the `view` function that the input, color button, and reset button contain.

Remember that the color button and reset button each had an attribute like this: 

```javascript
style: `border-color: ${vnode.attrs.color.border}`
```

This is actually referencing the object that's passed in as the attributes argument in the nested elements in our App component i.e. `{ color: State }`. The attribute is accessible in the `view` function for our color button and reset button components as `vnode.attrs.color`. So this explains the `view: function(vnode){...}` that we saw earlier, as `{ color: State }` is passed in as the `vnode` argument. 

Our button components can now access our global variable `State`. We see that they're specifically referencing `vnode.attrs.color.background` (color button) and `vnode.attrs.color.border` (reset button), which translates to `State.background` and `State.border`, respectively. So when an event is successfully triggered, new colors (based on the input value) are assigned to the buttons. The UI is updated instantaneously when Mithril detects this change in color for the components.

Here's the final result:

{% codepen https://codepen.io/andrew_chou/pen/qVedOJ %}
  

### Step 4: Final Thoughts

I know that this post was pretty dense, but I tried my best to make it easy for beginners to follow. To recap, my first implementation of this app didn't have that much JavaScript, but I had to write some HTML boilerplate. The rewritten version contained a lot more JavaScript but no HTML whatsoever. It's difficult to understand the tradeoff with a really small app like this one, but using Mithril and idea of components was logical and relatively simple to implement in this case, and it's definitely useful when you try to create more complex applications. 

Hopefully you learned something from this or at least enjoyed reading about my process. If you have any suggestions for me (or want to point out something that I messed up on), let me know! This is actually my first technical post, so I welcome the feedback. I'll hopefully have more opportunities to write more in the near future :)


Thanks for reading!