Ember for Designers: Alternate States

Christian Reuter

Product designers typically start by designing for content, and leave alternate states as an afterthought (or worse, forget about them altogether). They’re critical to a usable experience, and can help reinforce mental models and visibility of system status.

We’re going to walk through how we can use Ember to design for three of these in particular: empty, loading, and error states.

Empty States

One of Ember’s most powerful features is handling live conditionals in the browser, without a page refresh. This enables rich interactions and manipulation of interfaces and content.

Empty States give us the opportunity to inform, educate, and delight. It’s a unique part of product design that allows us to think more creatively and express some personality. These are occasions to congratulate users for reaching inbox zero, or teach new users how to get content into their feed.

Our introductory post to this series talked about getting an each/else out of the box, which saves us from having to write a separate if statement to see if an array is empty. Having this built in can be a helpful reminder while designing— when there’s an {{each}}, there should usually be an {{else}}.

Each/Else example

In the template:

<ul>
  {{#each email}}
    <li>
      {{subject}}
      <button {{action "delete"}}>Delete</button>
    </li>
  {{else}}
    <li class="empty-state">
      WooHoo!
    </li>
  {{/each}}
</ul>

We can use similar conditionals to only display part of our template in Rails, too. The difference is that we get one UI state per page load, whereas a single template in Ember can show any number of configurations at any given time.

We can act immediately on user input, giving instant feedback, totally bypassing any latency from a trip to the server. This enables us to design richer experiences by reducing both the friction and development cost of interaction.

Loading States

Ember gives us a loading substate to customize transitions between routes. We usually get a spinner in the tab, but the browser doesn’t know when there isn’t an actual page load.

We can compensate by adding a template named loading, which will set a default loading state for every route transition. This makes sense if you want some sort of generic loading animation, like a spinner, or maybe simple View agnostic loading… text.

In app/templates/loading.hbs:

<h2>Loading &hellip;</h2>

If you want a loading state more specific to the route you’re transitioning to, you can add a loading template as its sibling.

For example, if transitioning to app/templates/people/person/profile.hbs, Ember would first look for a loading.hbs in the person directory. If it didn’t find one, it would move up to the people directory, and then continue on up to the templates’ root.

This is useful for transitory states where we can preload dummy content in a more graceful way. Facebook elegantly handles this type of transition by loading placeholder content in its feed, then replacing it with live content once it’s loaded.

Facebook loading state

Read more about Ember loading states in the guides.

Error States

Error substates work much the same way as loading. In the event that an error is encountered on a page transition, Ember will load the most locally scoped error.hbs template to whatever it is that you’re transitioning to, starting with its siblings.

You can even include the {{message}} or {{stack}} in your template to save a trip to the console, but it’s probably best to only do that in a development environment. User-facing error messages should always be expressed plainly, speaking their language.

Note: Rather than adding an error or loading template, you could explicitly define a new ErrorRoute or LoadingRoute. See the guides for more details.


Designing for the edge cases surrounding a lack of content is essential. These alternate states can help educate, inform, and delight, ultimately contributing to a more usable, satisfying experience. Ember makes it a little bit easier.