Ember for Designers: Components

Christian Reuter

Imagine a world where you aren’t confined to the existing standard for available HTML tags. You aren’t limited to <h1>s and <div>s and <section>s. You can define and use your own application-specific DOM elements for more semantic and readable markup.

The W3C is currently working on a Custom Elements specification that offers that promise, and Ember components make that promise a reality we can use today. Because Ember components are an early implementation of Custom Elements and following the spec as closely as possible, what we define today should be usable in other frameworks tomorrow.

Consider an inline-edit element, which you might use in many places of an application. With components, you only need to write the markup once to use it in many contexts.

Inline Edit

The Template

To create a new component, make a new template who lives in the components directory.

In app/templates/components/inline-edit.hbs:

{{#if editing}}
  <form>
    {{input value=value}}
    <a href="#" {{action "cancelEditing"}}>Cancel</a>
    <a href="#" {{action "stopEditing"}}>Save</a>
  </form>
{{else}}
  <a href="#" {{action "startEditing"}}>{{value}}</a>
{{/#if}}

(Note: components must have a dash in their name to prevent collisions with future HTML elements.)

Our example needs to keep track of editing state, but if your component only needed markup, you’d be finished. You could already use your custom {{inline-edit value=name}} element wherever you’d like.

The CSS

While Ember components don’t specifically bundle or attach styling (Custom Elements can using the Shadow DOM), I like having a stylesheet per component. I’d create a corresponding app/styles/components/_inline-edit.scss to keep everything nice and tidy.

The Class

You can optionally extend components with properties, variables and actions by creating a component subclass.

For the inline-edit, we’ll want to set set the custom editing property’s default to false, and also define our actions. (I’ll sometimes prototype these interactions with jQuery, and let a developer come in behind me to move everything to the component.)

In app/components/inline-edit.coffee:

InlineEditComponent = Ember.Component.extend
  editing: false

  actions:
    startEditing: ->
      @toggleProperty("editing")

    stopEditing: ->
      @toggleProperty("editing")
      if @get("isDirty")
        @get("content").save()

    cancelEditing: ->
      @toggleProperty("editing")
      @get("content").rollback()

Other examples

Components are powerful and composable. They conveniently reflect how I already think of components in Sass, so I love the symmetry.

We’re using them for avatars in one application, where we sometimes want to optionally show the username.

{{user-avatar url=user.avatarURL}}

or

{{user-avatar url=user.avatarURL showName=true}}

You might also use them for reusable parts like dropdowns, form groups, or other navigation patterns.

Additional Reading

You can extend Ember components further by customizing their wrapping tag or class names. You can even wrap content in a component, which is useful for things like dropdowns or accordions.

Read the Ember 2.0 Road map to see what’s coming next. We have some fun new toys to look forward to, like a new HTMLBars syntax.

{{user-avatar url=user.avatarURL}}

will change to:

<user-avatar url={{user.avatarURL}}>

Read Ember’s guides for a closer look of current implementation. They’re fantastic.