Fable and Fable-Elmish Step-by-Step: Creating a Calculator
Learning by Doing
In this tutorial we are going to learn how we use Fable by creating a simple calculator application running in the browser. This tutorial is aimed at beginners and is intended to be as self-contained as possible. I assume you are comfortable with F#.
Fable-Elmish: A library for building user interfaces, heavily inspired by Elm and it’s clean architecture. First, I will focus on boilerplate code and the setup of a Fable-Elmish project. Then we will discuss the Elm architecture and from there we start with a simple implemention of a counter app to illustrate the concepts of Elm. After that the actual calculator app follows.
Our application will have the following project structure. This structure should be re-usable for similar small projects.
elmish-calc (root folder)
| -- build
| -- app.js (generated after compilation)
| -- public
| -- index.html
| -- bundle.js (generated after bundling)
| -- src (here the F# source files)
| -- app.fsx (our main F# script file)
| -- package.json
| -- webpack.config.js
| -- build.js
Start by creating a root folder and create a similar structure with empty files , excluding
bundle.js because these will be generated.
src directory is where our F# code will be. For this application it is one fsharp script (app.fsx) but you could put multiple files there or even a fsharp project (.fsproj). For now we will keep it simple and just stick with one script file.
bundle.js inside the
You might ask, “Can we change the default output of Fable so that the browser understands it directly without using Webpack?”. Yes we can, but I thought it is a good idea to let Webpack do that for us. Webpack is used frequently with Fable projects so it is worthwhile getting familiar with it. It is a very powerful tool and bundling is just one of the many things it can do. Please refere to their website to learn more.
The work flow goes like this:
F# source files -> Fable -> Js source files -> Webpack -> Js bundle file . As you have already noticed, you will need quite some dependencies to get the process going. You define these dependencies inside package.json.
npm install inside a directory that has
package.json npm will download all libraries and developement dependencies such as compilers and bundlers inside a directory called
node_modules . Lets have a look at our package.json
As you can see, there are two main sections inside package.json, the
devDependencies . Developement dependencies (
npm install and see a new directory called
node_modules created where all these libraries, compilers and loaders will be.
Note that we are pulling
fable-compiler version 0.7.48, so this tutorial is best applicable to that version.
This is the settings file for the bundling process. It might look quite intimidating so for now I will ask you not to think about it too much.
The important part to understand now is this:
It tells webpack to look at the file called
app.js (will be generated by Fable) inside the
build directory and bundle that into a directory called
public with filename
build.js is run by node (using
node build.js from the command line), it will clean the
build directory. Then tell Fable to look for
src/app.fsx and compile that to the
build directory, effectively generating
app.js which will be handed to
webpack for bundling.
is where you put the fable configuration.
This is the html page that will embed the app, the
div with id
elmish-calc is the placeholder where the app will be mounted.
As you can see, you need no other external dependecies to pull from CDN or other services because everything we needed was inside
node_modules and webpack made sure it all goes to that one
Here is where we implement the application. First we reference the dependencies:
Before we dive in with our calculator app, I think we should start with something simple like a counter app. This will help demonstrate the ideas and concepts of the Elm Architecture.
The Elm Architecture
Fable-Elmish follows the elm achitecture for writing the apps. There are many good guides on this subject like the official one here and it is highly recommended that you take a look there. But I intended this tutorial to be self-contained so I will try to explain it myself. Here we go!
An Elm program has four main parts:
- Update function
- View function
Model is the data you want to keep track of while the app is running. It captures the state of the app at any point in time during execution. In a counter app we would like to keep track of an integer we call
Count so we define our model as follows:
Messages are objects that contain data. These data are mostly sent (dispatched) by user interaction from the app. For example when a user clicks a button or enters text in a text field, a message is then sent to the
update function along with with current model. In our counter example. We want messages that are sent when the user wants to increment or decrement the counter. We define our messages like this:
When a message is dispachted, the
update function recieves it along with the current model. Then it computes based on this information the next model or the next state of the app. We implement it as follows:
This is a function that takes the current model, a dispachter function, and returns a view. In our counter, it is as simple as this:
The reason we are returing ReactElement as output has to do with the implementation of Fable-Elmish. Fable-Elmish defines the idea of a
Program that executes a dispatch loop based on the Elm architecture. However, the view part of this program is not tied to a specific user interface library. It has adapters to work with and leverage different user interface libraries. In our case we are using the React implementation but other implementations can be used. Currently React and ReactNative are supported. Snabbdom support is now being implemented as per the time of writing.
Now we have all the parts we need to run the app. We use the
The full app.fsx for the counter app
To build the app:
npm run build
npm run bundle
npm installdownloads the dependencies. (run only once)
npm run buildcalls fable compiler to compile F# code.
npm run bundlecalls webpack to bundle the output of fable coompiler into one
You will repeat
npm run build and
npm run bundle evey time you want to re-compile your app to see your changes. You might think it is too slow and you would be right. Usually we would enable what we call Hot Reloading to watch for our changes and re-compile automatically and fast. We will not use that in this tutorial.
After that go to your
index.html and you should see a simple counter like the following, demo here.
Now we begin with our calculator. Basically, it has the same structure as with our counter application but with diffirent implementations for
First we want to define a model that captures the state of the application at any point while the app is running. Usually the user has to go through a series of clicks to calculate something. For example. to calculate 9 + 2. The sequence of clicks is:
[9; +; 2; =] becomes 
When the user reaches the last element of the sequence, i.e. clicks on
= , we evaluate the
[9; +; 2] to get
 and show that the answer is 11 to the user. Let us first define what the user can click on:
The representation of our sample sequence becomes:
[9; +; 2] => [Const 9; Plus; Const 2]
What we want to keep track of is not one
Input but rather a list of
Input so this is going to be our model:
For messages we will only have one type of messages. Namely, a message that captures what the user clicked. This is very convienient when implementing our
update function. When the user clicks something, a message of the clicked button is dispatched. Then the update function gets the current model (the sequence of tracked clicks) and what the user clicked. Based on this, the update function will compute the next state of the app. Diffirent scenario’s can occur, for example:
// user clicks on digit 9 as his/her first message
update (Const 9)  => [Const 9]
// user clicks on operation as his/her first message, then do // nothing and return the same model because you have to have a // Const x as your first click.
update (Operation x)  => 
// user clicks op operation after he/she had clicked on digit
update (Operation x) [Const y] => [Const y; x]
// user clicks on two digits after another, we "concat" the // digits i.e. concatInts 2 4 => 24
update (Const 3) [Const 4] => [Const 34]
The list goes on but hopefully now you have an idea of how the update function will be implemented. We check the message we got (what the user clicked) and what we already have (the current model) and compute what the next model will be. Our Messages type will be:
We will also have some helper functions like
solve , and a partial active pattern
Operation to easily match with an operation like
Just as I illustrated with the scenario’s, we implement the update function by matching on what message we got and the model we already had and return a new model:
The function above contains all the logic for the calculator! It is the beauty of F# that lets us describe this logic the same way we think about it.
If you look carefully, you will see that there are missing patterns for inputting negative numbers i.e.
[Minus; Const x] => [Const (-x)]. The implementation for this pattern is left as an exercise for reader.
Just like with the counter, the view function for the calculator will have the signature:
view :(model: Model) (dispatcher: Messages -> unit) : ReactElement
But we will break this function in smaller helper functions and use these small functions to construct the main view function. We want to re-use the function that makes a digit and the the function the makes an operation button. These are implemented as follows
Notice that when a helper view function wants to dispach an action, it takes the
dispatcher : Messages -> unit as argument. The main view function passes the dispatcher down to it’s child view functions.
The code for the
opString is omitted here because it is not of great importance, you can examine the code when we take a look at the whole file.
Now let’s take a look at the main view function, it should look straightforward.
and the last part to run app is not changed:
Full app.fsx for calculator:
Now recompile with
npm run build
npm run bundle
Navigate to your index.html to see the calculator. There you go, you have now made a calculator with Fable and Fable-Elmish.
Full source code can be found here on github.
Using Fable, we are bringing the power of F# to the browser. With Fable-Elmish we were able to think about and write our app cleanly according to the Elm architecture. We saw a glimpse of what you can do with Webpack. I enjoyed writing this article and I hope you learned something from it and also had fun along the way.