Tutorial: Building a ToDo app with OOjs-UI (Part 1)

In this post we’ll walk through creating a simple ToDo JavaScript app with the OOjs UI library, which was created by the Wikimedia Foundation. OOjs UI has a lot of power under the hood and a lot of potential for super-powerful JavaScript applications in your browser — so we will start small and grow as we go, hopefully giving you a taste of the library and its concepts.

This post and the accompanying code is available on Github. Corrections and pull requests are welcome!

OOjs UI itself is licensed under MIT. The code we will create is licensed under GPLv2.

Setup and prep

First, we’ll have to get the libraries we will use: jQuery, OOjs and OOjs UI.


In your project directory, create a assets/lib/ folder that will hold our necessary libraries:

  1. You can download jQuery from the official website. We’ll be using version 1.12.1
  2. OOjs and OOjs UI are available from the official repositories, and there are two ways to download the files we need (see next section).

There are two main ways to get the files for both of these libraries, depending on how comfortable you are with development environment and working with git.

Getting OOjs and OOjs UI from the git repo

If you’re comfortable with git and gruntjs, this is the best way to work with OOjs and OOjs UI library files, as those will give you the most updated files each time:

  • Clone the repository
    • OOjs – git clone git@github.com:wikimedia/oojs.git
    • OOjs UI – git clone git@github.com:wikimedia/oojs-ui.git
  • Run npm install in each of the repositories to install the necessary packages.
  • Run grunt build in each of the repositories. This will populate their dist/ folders, which is where you get the library files to use.
    • For OOjs, we will use the oojs.jquery.js file (place that one in your assets/lib folder)
    • OOjs UI is a robust library with the option of separating modules. We don’t need most of the files in the dist/ folder, all we need are these files to be copied files into your assets/lib/ooui/ folder:
      • dist/oojs-ui.min.js
      • dist/oojs-ui-apex.min.js
      • dist/oojs-ui-apex.css
      • dist/themes/apex

Getting OOjs and OOjs UI from the demo zip

If you don’t want to mess with git and grunt, you can download the demo files and extract the necessary library files directly from it, trusting that I did the job for you.

Download the zip file here.

The only caveat here is that the demo zip will likely not be updated as often as OOjs UI is updated, so be advised that you may be using an older library version.

Project files

We will start with two files for our project – the JavaScript initialization file and the CSS file.

  • todo.css – Create an empty file todo.css and place it in the main directory – we will use this file later for all of our custom CSS styling.
  • assets/init.js – Create a new empty file init.js and place it in the assets/ directory. This will be our initialization script.

Add to the project

Next, we will attach those files to our html page. This is how our basic page should look like now:

We will use the wrapper div element to inject our application into.

Building the base

So now that we have our basic page, we need to start writing code. Our ToDo app should have two main pieces to start with: An input to add a new item, and a list displaying all items that have been added. Since a ToDo list allows us to show a list of items that can be selected, the best starting point for this is an OO.ui.SelectWidget — so that’s what we’ll start with. You can see a demo of all OOjs UI widgets in the official demo page.

Let’s break this up and see what we did there.

One of OOjs UI’s principles is to separate the data from the UI, so each one of the widgets we’re creating is first and foremost an object that is separate from the DOM. That object contains the DOM element itself in the $element property, which we use to attach to the document, but the behavior itself (as we will soon see) is done through the general OOjs UI object.

So in short, we created two widgets — a text input and a select widget — and then attached their $element to the document. If you load your page, it should have the title and an input. The list is invisible because we don’t have a way to add elements to it yet — so let’s do that now.

Adding items to the list

We have our input, and we have the list, and now we need to connect them. OO.ui.TextInputWidget emits several events – one of them is simply “enter” when the enter key is pressed (You can see all events in the documentation). Let’s make our input add an item to the list when we hit the “enter” key.

Since the list is an OO.ui.SelectWidget we should add into it an OO.ui.OptionWidget.

That would add an item to the list. But what if we are trying to add an item that already exists? Let’s add a condition that checks whether the item exists first before it is added:

We now are able to only add unique items to this list. When an item that already exists is added, we attach the class “todo-error” to the input. For it to actually show something, we need to define it in our CSS file. Add this to your todo.css file:

Now let’s try our new app:

Adding items

Adding a duplicate

It works! Now, let’s add a little bit of extra flair to the app.

Custom styling

Let’s make sure that our list and our input are styled a bit better, and add a placeholder to the input. Let’s go back to the piece in our code where we created the widgets, and add configuration to both:

The above configuration adds CSS classes to the widgets and a placeholder text to the text widget. We can now go edit our todo.css stylesheet, and add styles. Notice that we can also style the underlying objects, which (for now) we will do by calling their oo-ui-style class:

That’s it. Now reload your app and look at your wonderful result.

The complete code

We now have a basic ToDo app. Yay! Here’s the full code of our init.js

In the next part, we’ll see how we can add more functionality, like storing and reading specific data on each object.

Go to part 2 of this tutorial

Tags: , ,

Trackback from your site.