Animation Directives and CSS Hooks
AngularTS integrates animations into the same lifecycle that drives structural
directives. Add the animate attribute to an element and the $animate service
applies entry, exit, and class-change hooks at the appropriate DOM update.
How $animate integrates with directives
Structural directives such as ng-if, ng-repeat, ng-show, ng-hide,
ng-switch, and ng-include check for animation data before manipulating the
DOM. When animate is present, they delegate DOM operations to $animate:
| Operation | Without $animate | With $animate |
|---|---|---|
| Insert element | element.after(clone) | $animate.enter(clone, parent, after) |
| Remove element | element.remove() | $animate.leave(element) |
| Toggle class | element.classList.add(cls) | $animate.addClass(element, cls) |
| Swap classes | el.add(a); el.remove(b) | $animate.setClass(element, add, remove) |
This means you can add CSS transitions to any structural operation simply by
adding the animate attribute and writing the corresponding CSS rules.
CSS animation hook classes
When $animate performs an operation it applies a sequence of CSS classes in
two frames to give the browser time to set up the transition:
Element enter
ng-enter → ng-enter + ng-enter-active → (classes removed)
Element leave
ng-leave → ng-leave + ng-leave-active → element removed
Element move (ng-repeat reorder)
ng-move → ng-move + ng-move-active → (classes removed)
Class add/remove
ng-CLASS-add → ng-CLASS-add + ng-CLASS-add-active → CLASS applied
ng-CLASS-remove → ng-CLASS-remove + ng-CLASS-remove-active → CLASS removed
.card.ng-enter {
opacity: 0;
transform: translateY(-8px);
transition:
opacity 0.25s ease,
transform 0.25s ease;
}
.card.ng-enter-active {
opacity: 1;
transform: translateY(0);
}
/* Fade out when the element is removed */
.card.ng-leave {
opacity: 1;
transition: opacity 0.2s ease;
}
.card.ng-leave-active {
opacity: 0;
}
Animating ng-repeat lists
ng-repeat triggers ng-enter and ng-leave animations for items added to or
removed from the collection. Add the animate attribute on the repeated element
to opt in.
<ul>
<li class="task-item" ng-repeat="task in tasks" animate>
<span ng-bind="task.title"></span>
<button ng-click="removeTask(task)">Remove</button>
</li>
</ul>
animation: slideIn 0.25s ease forwards;
}
.task-item.ng-leave {
animation: slideOut 0.2s ease forwards;
}
.task-item.ng-move {
transition: all 0.3s ease;
}
@keyframes slideIn {
from { opacity: 0; transform: translateX(-16px); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes slideOut {
from { opacity: 1; transform: translateX(0); }
to { opacity: 0; transform: translateX(16px); }
}
.controller('TaskCtrl', ['$scope', function($scope) {
$scope.tasks = [
{ id: 1, title: 'Design wireframes' },
{ id: 2, title: 'Write tests' },
{ id: 3, title: 'Deploy to staging' }
];
$scope.removeTask = function(task) {
const idx = $scope.tasks.indexOf(task);
if (idx !== -1) $scope.tasks.splice(idx, 1);
};
}]);
Animating ng-show / ng-hide
ng-show and ng-hide both apply a temporary ng-hide-animate class alongside
ng-hide when the $animate service is active. This class serves as the
transition anchor:
<div animate>{{ message }}</div>
transition: opacity 0.3s ease, max-height 0.3s ease;
overflow: hidden;
}
/* State when hidden */
.notification.ng-hide {
opacity: 0;
max-height: 0;
}
/* Applied during the animation frame to enable the transition */
.notification.ng-hide-animate {
display: block !important;
}
JavaScript animations
Register JavaScript animation hooks with the module’s animation() method:
angular.getModule('app').animation('.flip-card', function () {
return {
enter: function (element, done) {
// Use Web Animations API or any library
element.animate(
[{ transform: 'rotateY(90deg)' }, { transform: 'rotateY(0deg)' }],
{ duration: 300, easing: 'ease-out' },
).onfinish = done;
return function (cancelled) {
if (cancelled) element.style.transform = '';
};
},
leave: function (element, done) {
element.animate(
[{ transform: 'rotateY(0deg)' }, { transform: 'rotateY(-90deg)' }],
{ duration: 250, easing: 'ease-in' },
).onfinish = done;
},
};
});
<div ng-repeat="card in cards" animate>{{ card.content }}</div>
Tip: JavaScript animations and CSS animations can coexist on the same element. The
$animateservice runs CSS animations and JavaScript animation hooks in parallel, callingdoneonly after both complete.
Animation and the HTTP directives
The HTTP directives (ng-get, ng-post, etc.) also support the animate
attribute. When present, swapped content uses $animate.enter and
$animate.leave instead of direct DOM manipulation:
<div
ng-get="/api/posts"
trigger="load"
swap="innerHTML"
animate
class="post-content"
></div>
opacity: 0;
transition: opacity 0.4s ease;
}
.post-content.ng-enter-active {
opacity: 1;
}
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.