Get the Newsletter

Animation

The basics of using the animation plugin for Aurelia.

Introduction

Animations are the way we bring our applications to life. An animation lets an element gradually change from one style to another, giving it the ability to smoothly alter its size, color, etc. over time.

A key goal in building animation support for Aurelia was to enable a flexible solution that allows you to choose whatever animation library you like. As a result, you're neither limited to a proprietary API nor to a certain style for how to implement your animations. To enable this flexibility, Aurelia's animation system is built around a simple animation interface , which is part of its templating library.

In this article we'll cover the official CSS animation plugin for Aurelia, aurelia-animator-css. This plugin is one concrete implementation of the interface mentioned above. However, you can also use our official aurelia-animator-velocity plugin if you prefer the Velocity library, or you can write your own plugin based on the interface above, for example if you prefer to use something like Greensock.

Many kinds of animation can be applied to your elements, but in this article we'll demonstrate the common cases by using simple CSS animations; mainly, animation when navigating between views with the router, and animating incoming and outgoing elements of a repeater.

Installing The Plugin

If you are using the CLI or Webpack, you can install the plugin from NPM:

    
  npm install aurelia-animator-css
  
  

or

    
  yarn add aurelia-animator-css
  
  

If you are using JSPM for client dependencies, then you can use this command:

    
  jspm install aurelia-animator-css
  
  

If you created your app with the Aurelia CLI, chances are you already have the plugin installed as a dependency.

If you are using an older version of Aurelia CLI, prior to 1.0, with RequireJS/SystemJS loaders, you should add aurelia-animator-css in the dependencies part of the bundle in your aurelia.json file.

Configuring The Plugin

In your main.js within your src folder, simply call the plugin API with the animation plugin's name:

    
  import {PLATFORM} from 'aurelia-pal';
  
  export function configure(aurelia) {
    aurelia.use
      .standardConfiguration()
      .developmentLogging()
      .plugin(PLATFORM.moduleName("aurelia-animator-css")); //<-- add this
  
    aurelia.start().then(a => a.setRoot());
  }
  
  

PLATFORM.moduleName should not be omitted if you are using Webpack.

You could also configure plugin to explicitly handle enter/leave animation ending (will be described below):

    
      .plugin("aurelia-animator-css", cfg => cfg.useAnimationDoneClasses = true)
  
  

Demo

Before we get started setting up the animations themselves, take a look at a demo of what we'll build out.

Using The Plugin

First we need to declare some keyframes animations that we can later hook on our elements.

Don't forget to add the appropriate vendor prefixes if you target old browsers.

    
  @keyframes SlideInRight {
    from {
      transform: translateX(100%);
    }
  
    to {
      transform: translateX(0);
    }
  }
  
  @keyframes SlideOutRight {
    from {
      transform: translateX(0);
    }
  
    to {
      transform: translateX(100%);
    }
  }
  
  @keyframes SlideInLeft {
    from {
      transform: translateX(-100%);
    }
  
    to {
      transform: translateX(0);
    }
  }
  
  @keyframes SlideOutLeft {
    from {
      transform: translateX(0);
    }
  
    to {
      transform: translateX(-100%);
    }
  }
  
  @keyframes FadeIn {
    to {
      opacity: 1;
    }
  }
  
  @keyframes FadeOut {
    to {
      opacity: 0;
    }
  }
  
  

These are pretty typical, standard CSS animations. There's nothing really special to note about them. You may not need them all, or you may add new ones according to your needs, but they should give you a solid start.

Now we also need CSS classes that use those animations, so we can later add those classes on our elements to activate the animations.

    
  .animate-slide-in-right.au-enter {
    transform: translateX(100%);
  }
  
  .animate-slide-in-right.au-enter-active {
    animation: SlideInRight 1s;
  }
  
  .animate-slide-out-right.au-leave-active {
    animation: SlideOutRight 1s;
  }
  
  .animate-slide-in-left.au-enter {
    transform: translateX(-100%);
  }
  
  .animate-slide-in-left.au-enter-active {
    animation: SlideInLeft 1s;
  }
  
  .animate-slide-out-left.au-leave-active {
    animation: SlideOutLeft 1s;
  }
  
  .animate-fade-in.au-enter {
    opacity: 0;
  }
  
  .animate-fade-in.au-enter-active {
    animation: FadeIn 1s;
  }
  
  .animate-fade-out.au-leave-active {
    animation: FadeOut 1s;
  }
  
  .animate-fade-out.au-left {
    opacity: 0;
  }
  
  

Essentially, all that is needed to make an animation work is to define CSS classes with special predefined suffixes. You get the chance to use preparation classes, added before the actual animation starts, as well as activation classes, used to trigger the actual animation. Take a look at the following table for all available options.

Method Description Preparation Animation activation Animation ended
Enter Element enters the DOM au-enter au-enter-active au-entered
Leave Element leaves the DOM au-leave au-leave-active au-left
addClass Adds a CSS class [className]-add [className]
removeClass Removes a CSS class [className]-remove

Classes au-entered and au-left are only added if useAnimationDoneClasses property has been configured. au-left class could be usefull in case of animating disappearing of an element as between au-leave-active class removal and dom node removal, the frame could be rendered, that could make the element to flicker ( more details ).

Methods addClass and removeClass are belong to Animator.

removeClass animation does not trigger if an element does not have either [className] or [className]-add (pending addClass animation) CSS class.

Working with Default Animation Triggers

We need to give our elements the class au-animate to tell Aurelia that those elements can be animated. Additionally, we should apply a specific animation from the ones we have created above (i.e animate-fade-in). Once that's done, every time the element enters or leaves the DOM, the animation will kick-in.

As an example, we may have multiple li elements rendering in a repeater and we would like them to animate in and out using the fading effect we declared above. We can declare that like this:

    
  <ul class="au-stagger">
    <li
      repeat.for="todo of todos"
      class="au-animate animate-fade-in animate-fade-out"
    >
      <input type="checkbox" checked.bind="todo.done">
      <span css="text-decoration: ${todo.done ? 'line-through' : 'none'}">
        ${todo.description}
      </span>
      <button click.trigger="removeTodo(todo)">Remove</button>
    </li>
  </ul>
  
  

Notice the au-stagger class on the ul container. It is used to delay the animation between each one of the lis so they don't animate in simultaneously.

    
  .au-stagger {
    animation-delay: 500ms;
  }
  
  

If we would like to animate the views that are rendered in a router-view, we can use the same method. We need to add the au-animate class on the first child of the view and add the desired entering/exiting animations.

    
  <template>
    <div class="au-animate animate-slide-in-right animate-slide-out-left">
      ...
    </div>
  </template>
  
  

We'll also want to set the swap-order attribute of the router-view element. This controls how the animations between the old view and the new view are ordered in time. More information on the available options can be read about here and you can play with their effects in the demo above.

Summary

By adopting the aurelia-animator-css plugin, adding animations to your app is as simple as including a few standard CSS animations and applying a few classes to selected HTML elements. However, this just scratches the surface of animation in Aurelia. If you need more power, you can implement your own animation system by creating a class that implements the standard Aurelia interface and plugging it in, opening up endless possibilities.