CSS Transitions with Ember.JS Components

Trying to build an off-canvas panel using Ember.JS components was proving difficult. It did not help that most the results still referenced the now deprecated Ember.View.


I had built the off-canvas panel to animate using CSS3 transitions and animations instead of a more traditional JavaScript approach. The implementation required jQuery to add the .is-visible class to a <div class="cd-panel">...</div>.

Final Answer

The answer I found was to use RSVP.js implementation of Promises that comes as part of Ember.JS.

// app/components/story-panel/component.js
import Ember from 'ember';

export default Ember.Component.extend({
  actions: {
    close: function() {
      var promise = new Promise(function(resolve, reject) {


        setTimeout(function() {
        }, 600);
      promise.then(function() {
        return this.sendAction('close');
  becomeVisible: function() {
    setTimeout(function() {
    }.bind(this), 100);

Other considered options

In my hours long search for an answer to this problem, I discovered another approach that seemed to work (though for unknown reasons). The solution that relied upon the usage of Ember.run.next.

This did seem to work for the becomeVisible method, but I could not translate that into a working close action.

As far as to why Ember.run.next worked, I am still unsure. Looking at the Ember documentation for this method it calls out that there are normally better ways to resolve issues requiring the #next call.

Code sample

<div class="cd-panel from-right">
  <header class="cd-panel-header">
    <h4>View Story Details</h4>
    <a {{action 'close'}} class="cd-panel-close">Close</a>

  <div class="cd-panel-container">
    <div class="cd-panel-content">
// app/iterations/route.js
import Ember from 'ember';

export default Ember.Route.extend({
  displayStory: false,
  model: function(params) {
    return this.store.query('iteration', params);
  actions: {
    openStoryPanel: function(story) {
      return this.render('story-panel', {
        outlet: 'story-panel',
        into: 'application',
        model: story,
        controller: 'application'
    closeStoryPanel: function() {
      return this.disconnectOutlet({
        outlet: 'story-panel',
        parentView: 'application'
<!-- /app/templates/application.hbs -->
{{outlet "story-panel"}}

<!-- /app/templates/story-panel.hbs -->
{{story-panel model=model close='closeStoryPanel'}}

Justin Smestad

Read more posts by this author.

Subscribe to Overstuffed Gorilla(s)

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!