Building web apps, one Brick at a time!

Note: These are the notes on my talk about Mozilla Brick at Over The Air 2013. Sadly it wasn't recorded, and I got kind of nervous and forgot to press the "REC" button in Quicktime, so I didn't "screencast" it either. You can also check the original slides for maximum impact.

Mozilla Brick

UI components for modern web apps

Brick Hello everyone! I'm going to tell you all about Brick which is a set of UI components / library developed at Mozilla to make it easier to develop web apps. So everyone is talking about components, and Web Components and stuff, but...

Hold on

What is a "component"?

I think it's important we define what is a "component" beforehand.

"a constituent part; element; ingredient."

That's what the dictionary says. But sometimes it's better to look at examples. So that could be...

Screws

picture of screws (picture by apeofjungle)

Resistors

picture of resistors (picture by oskay)

Doorbell

picture of doorbell (picture by neosnaps)

Or maybe even a doorbell!

What is common to all these things is they are like black boxes. You just use them. You could, of course, open them to see what is inside, but you generally don't do it, unless you're very curious (like me).

And a web component?

So how does it relate to web components?

It's the same

It's the same. Web components are things you use without having to know how they work in the inside.

Buttons

For example, buttons.

Range

Or the input type=range. It looks a bit silly that huge, doesn't it?

Web-bell

Or even the web-bell! A web-bell?

That's just a component I created! If you press it, it plays a doorbell sample. I'll come back to that later.

(See slides for running the web-bell)

So, web components

They are like any other HTML element but also have got...

  • Custom behaviour
  • Custom appearance

The key is custom

They will allow us to build components before they are standard, or anyone comes up with the conclusion that a new component is required.

Although the spec calls them widgets

But I don't quite like the "widgets" word. Anyway! I know some people might be wondering...

Why Web Components?

Can't we just use divs?

html <div class="widget calendar ui theme-winter"> <div class="component-wrapper"> <div class="inner-content"> (ad nauseaum) </div> </div> </div>

Why Web Components?

Or maybe some jQuery UI plugin

javascript $( "#datepicker" ).datepicker( $.datepicker.regional[ "fr" ] ); $( "#locale" ).change(function() { $( "#datepicker" ).datepicker( "option", $.datepicker.regional[ $( this ).val() ] ); }); I promise I'm not making this up. This is copied and pasted from one of the examples in their website. How many times is 'datepicker' used in this example? Amazing. So yeah, basically my answer is...

No

image of Doctor Who saying no

Because...

With web components...

image of people clapping with conviction

  • Encapsulation
  • Reusability
  • Robustness
  • Expressiveness

you get all these benefits!

Ingredients for successful Web Components

But every great recipe requires some basic ingredients. In the case of Web Components, a nicely working implementation would require the following:

  • document.register
  • HTMLTemplateElement
  • Shadow DOM

... where document.register is used for telling to the browser that we want to use a new, custom component with a certain name (i.e. registering this component with your browser before using it, so it knows what you mean when you call document.createElement).

HTMLTemplateElement, or simply, <template> is used to create templates for your elements that can be instantiated later.

And Shadow DOM is, as some people call it, "like a Tardis", in that it is bigger in the inside than it looks from outside. It can contain a bunch of nodes and stuff, but the outside world just sees a "#shadow-dom" node, so it effectively encapsulates components.

But unfortunately the Shadow DOM is still not implemented in Firefox (bug 712622 is tracking it), which is why it's highlighted in red.

So... not ready yet?

image of group crying

Is everything lost? Are we doomed to keep using divs? Or can we do anything about it?

X-Tag to the rescue

Thankfully there is a solution! X-Tag!

Because...

X-Tag Shims all the things!!!11

(where appropriate)

All the things X-Tag is a library which makes it possible to start writing custom web components today, even if some features are not available in every browser. It will shim if required, or use the native features if there are present. For example, since the <template> is already implemented in Firefox, it would use the native object instead of shimming it. It also offers a unified interface across browsers--the same code you write is valid for all of them. And that's what Brick uses!

How does mark-up with Brick look like?

I presume you might totally be looking forward to see how code using Brick looks like. So there we go. This would be a minimal app:


<x-layout>

  <x-appbar>
    <header>
      Spiffy header!
    </header>
  </x-appbar>

  Marvelous content!

  <footer>
    Magnificent footer!
  </footer>

</x-layout>

As you can see we're mixing standard HTML5 elements (like header, footer) with our custom x-layout and x-appbar components. This works because web components are not special--once they have been registered, they act as any other DOM element. They can be created, appended to or removed from the DOM tree, etc.

But I bet there's something that might be itching you at this point...

Why the hyphen?

Why? Why are we using that hyphen in each one of our new, custom components?

The spec says

The custom element type identifies a custom element interface and is a sequence of alphanumeric ASCII characters that must match the NCName production and contain a U+002D HYPHEN-MINUS character
(source)

Or in other words: the name of a custom element must contain a hyphen.

So we took the X from X-Tag

And added a hyphen.

As simple as that. I think somebody asked at this point whether there was any sort of namespacing "authority". There is none! So use your best judgment. Probably if a certain set of components becomes popular, they will "own" that namespace.

The imperative way

Creating bricks out of nowhere

Image of Immanuel Kant But back to the components, up until this point we've been using them in a declarative way--defining them in our HTML code. Can we create them imperatively, i.e. from JavaScript? Well, of course you can (and I think I might have mentioned that already)

It's magic!

For example, for creating an instance of the calendar component that comes with Brick, you would just do the following:


var cal = document.createElement('x-calendar');
document.querySelector('section').appendChild(cal);

The Brick line up

These are the components that you get when you download Brick nowadays:

  • appbar
  • calendar
  • datepicker
  • deck
  • flipbox
  • iconbutton
  • layout
  • slidebox
  • slider
  • tabbar
  • toggle
  • togglegroup
  • tooltip

Some of them are quite explanative whereas others are more "abstract" and layout oriented--i.e you don't quite see them but they serve to divide the screen space in parts, align things, etc.

Get all the Bricks

So how do you get started with Brick in your project?

  1. Download the built files (brick.css & brick.js)
  2. Include the css file in your <head>:
    html <link rel="stylesheet" type="text/css" href="css/brick.css" />
  3. Include the js file at the end of your <body>:
    html <script src="js/brick.js"></script>
  4. Instead of window.onload, listen for DOMElementsLoaded

Customising

Your bricks, the way you like them!

Image of person breaking bricks with her head See, one finds quite weird things in the Internet. Apparently some people break bricks with their head? Well, if that's what they like... So yeah, there are two things you can do with regards to customising Brick...

Customising the appearance

The first thing you can do is changing the way they look. Also known as...

Give them a new layer of paint with CSS

This is how you do it:

  1. Include the brick.css file first
  2. Include your css file afterwards

Since there's nothing special about the CSS that Brick uses, we can just rely on the way CSS works.

Here's an example where we modify the default appearance of the x-appbar element:


x-appbar {
    background-image: linear-gradient(-180deg, #f0f 0%, 
        #f00 30%, #ff0 50%, #0f0 75%, #00f 100%);
    color: #fff;
    text-shadow: 1px 1px 1px #000;
    padding: 1rem;
    font-size: 2rem;
}

The default grey background was a little bit too neutral, so I made it rainbow-y. It's a bit dangerous once you start playing with CSS gradients. You never know when to stop.

Customising the bundle

You can also customise the built files (brick.js and brick.css). This is specially useful if you just want to use a couple of components and want to reduce the size of your code.

  • Online
  • Offline, command line with Grunt - we're on it

The online version will let you build your own Brick bundle once you tick a few checkboxes with the components you're interested in.

Or when you know what you're doing: no bundling

But you could go even further and use the "raw" components, without any type of bundling. This is what I do when I'm developing, because sometimes I need to modify the components themselves, or set breakpoints or any of those things we do when developing!

Although it's not recommended to do it in "production" websites as it's not exactly optimal.

  1. clone the brick repo and run make - this will run some commands that will result in a bunch of folders in the brick/dist directory (one per component)
  2. include dist/core/core.min.js
  3. include the components you need, e.g. dist/calendar/calendar.min.js

And now, the moment you all have been waiting for:

Bake your own bricks

Image of cookies getting cooked in an oven

Three simple steps

These are the bare minimum steps you need to follow to get a brick of your own:

  1. Include dist/core/core.min.js
  2. Write and include your-brick.js
  3. Write and include your-brick.css (optional)

What's in your-brick.js?

The first thing you need to do is registering your new custom element with the browser. We do this using the X-tag's register method:


(function() {
    xtag.register('your-brick', {
        lifecycle: {
            created: function() {
                this.innerHTML = 'I am a brick';
            }
        }
    });
})();

The method accepts an object that defines how a component behaves. The minimum thing we have to do for it to be useful is at least do something when a new instance of the component is created. So we'll act upon the 'created' lifecycle stage by setting our innerHTML to "I am a brick".

In this context, this is the component instance, as you might have already deducted.

Adding events

Of course, we can also listen to events! Say we want to listen to 'tap' events (this will work for touch and screen devices):


(function() {
    xtag.register('your-brick', {
        // ... here goes the lifetime code of before
        events: {
            'tap': function(e) {
                this.style.backgroundColor = 
                    '#' + Math.round(0xFFFFFF * Math.random())
                        .toString(16);
            }
        }
    });
})();

Whenever this component gets clicked, it will change its background colour to a randomly chosen one. See it in action.

Now you could open the web console in the example window, and type this:


for(var i = 0; i < 5; i++) {
  var brick = document.createElement('your-brick');
  document.body.appendChild(brick);
}

and that would end up adding five more bricks to the page. Each one is wholly independent from the rest, so you can click on each one and have it change its background, but not affect the others.

Something more advanced

So this is all fine and OK but perhaps not very exciting--could we build a complete app with Brick?

Pocket cutesy

So Ruth John --is Ruth in the room?-- ah, here she is! So she made an app called Pocket Kitten which provides you with pictures of cats. And I quite liked the app, and thought I could maybe redo it but using Brick. Also it's very convenient because it's her birthday today! So let's think of this as her present!

A new feature (apart from being built with Brick) would be that we will be showing animated gifs instead of static pictures. Also, since I wasn't sure whether we'd have Internet at this event, I've already downloaded all the gifs, so we get faster cutesy. This also means I've got to do a lot of search... or research.

Anyway, here's the app.

Interesting points to note:

The install button is hidden by default (with display: none), and shown only if a) the app is loaded in a runtime that supports installing, and b) the app hasn't been installed yet. This prevents you from showing an install button in cases in which it doesn't make any sense because there's no support for installing the app. For example, in Safari.

The tooltip, which is another Brick component, is removed when you tap the screen once. Since it's just a DOM element, we can safely remove it from the DOM and forget about it. Compare that with other UI libraries that require you to remove the listeners and the behaviours, and etc, before you can get rid of an element in the page.

We're still in beta

The current version is Brick 1.0 ß7*

So, expect bumps. For example, I would love to show you this app working on the simulator, but there's something breaking it, so I can't show you that. There's a bug already filed, so they know about that. It's important to file bugs! Always file bugs.

*Actually it was ß7 at the time of the talk, but it is ß8 now because a new version addressing the simulator breaking bug was released!

But bumps are good, because they highlight problems we didn't notice, and we try to fix them quickly. For example, the first day that it got to Hacker News' front page, we started getting reports about the calendar demo crashing browsers (specially Chrome).

It was a slightly hard to reproduce bug because it only happened when the computer's locale wasn't US--which is what the main developers were using! Since the calendar was expecting a US date format, and the rest of the world use a different (sensible) one, the component would enter in an infinite loop and crash the browser. UUUGH.

But thankfully Leon --the very talented intern that worked on this project this summer-- and Potch --his also very talented mentor-- quickly noticed the pattern in the bug reports, and fixed it. Brilliant!

Brick roadmap

So what is in the future?

Q1 2014

  • Brick 1.0
  • Mortar beta

Brick 1.0 would include the following features:

  • skinnability
  • accessibility
  • new components
  • modularity
  • 30+FPS in Firefox OS
  • Automated Testing
  • beautiful by default

Features with a checkmark mean they are already done.

Mortar is a series of templates that demonstrate how to build web apps, using a series of approaches. We have a basic stub, and are working on adding more, be it using Brick, or Brick with more frameworks such as Angular.

H1 2014

  • More components
  • Gaia skin (Firefox OS theme)
  • AppMaker integration - AppMaker is another Mozilla project to make building apps accessible to non-programmers
  • Brick 2.0

H2 2014

The second half of 2014 looks really exciting:

  • Flying cars
  • Ponies
  • Potch (project lead) in Fortune magazine
  • IPO

However...

Unicorns and rainbows are not in the roadmap

:-(

So I brought a few!!!

unicorns and rainbows

Thanks and... ask me questions!

@supersole Slides and code

Interesting questions people asked

I don't have the answer for all of them, but they're here for reference--and of course, if you have the answer, please do leave a comment, or write to me, or anything! Let me know!

Q: Is it possible to dispatch/listen to custom events? Apart from the ones x-tag already defines that are definitely not standard ('tap' for example) E.g. instead of listening for 'tap' events, you could listen for 'ring' events.

Answer by Arron Schaar (from X-tag fame): If 'ring' events are DOM events and are dispatched on the document then you can listen for them.

Q: Is it possible to mix Brick with Angular or other frameworks? How do you mix both types of views/widgets?

My answer during the talk: yes, and we're working on releasing examples (mortar).

Arron's more detailed answer, with link to an example: Mixing Angular and custom elements is actually very easy, especially if the custom element is controllable via attributes.

Check out this example where he's using Angular data binding to populate a sparkline element:


<x-sparkline points="{{symbol.ticks}}">

Q: how are things added to the x-tag registry? How do you get tags into it?

I wasn't too sure during the talk, but I asked Aaron and this is what he has to say: "If you click on the gear icon, there is a text box and an "Add" button that lets you add a component. There is also another registry at customelements.io. Bower is another option that allows developers to share components. All of our components are registered there--try bower search x-tag

to search for registered components"

Q: How do you make a bundle that includes js+css+external resources such as fonts, images, audio...?

A: Currently we have to ensure they're copied to wherever we use Brick but apart from base64-ing the hell out of the thing, I can't really think of a better way to include everything in just a couple of files. Maybe we could think of another deploy/build step? Or maybe this is something that needs to be addressed in HTML/browser land? Let's think about this if we have some spare moments/the will to do so!

Q: how close to Web Components is X-Tag? i.e. how much of an advantage X-tag has compared to just using raw web components support in the browser

X-Tag is "syntactic sugar" to make things a bit more consistent and kind of "defend you" against API changes. Specially since the spec is in flux and changes relatively often.

Update: pretty much as I was giving this talk, a post on Brick was published at the Mozilla Hacks blog. You should read it and watch the video if you're interested in learning more about Brick + Firefox OS, and also because Christian Heilmann and Potch are both awesome!

You might also be interested in reading this article introducing Brick by Leon Zhang.