Skip to content
Documentation/Choose the right tool

Search documentation

Type to search the documentation.

Start here

Choose the right tool

CSS, Angular's native animate.enter and animate.leave, Angular Movement and raw WAAPI all have a place. Use the simplest one that does the job.

Quick decision guide

You need… Reach for
Hover colour, focus ring, spinner CSS transitions / keyframes
One element fades or slides when it enters or leaves animate.enter / animate.leave (or moveEnter / moveLeave)
A panel that must finish leaving before its parent is removed Movement: *movePresence
A list where rows are added, removed and reordered Movement: *movePresenceFor
A card that changes between idle / selected / error states Movement: moveVariants or moveAnimation
Staggered reveal of siblings Movement: moveStagger
Progress bound to scroll position Movement: moveScroll (or CSS scroll-timeline where supported)
A single custom effect, nothing reused Raw WAAPI

CSS transitions and keyframes

If the motion is a function of a class or pseudo-class — a hover colour, a focus ring, a loading spinner, a menu that slides when a class is toggled — write CSS. It costs no JavaScript, works before hydration and is the easiest thing to maintain. Movement does not try to replace this, and you can mix both freely.

.button {
  transition:
    background-color 150ms ease,
    transform 150ms ease;
}
.button:hover {
  background-color: var(--accent-strong);
}
@media (prefers-reduced-motion: reduce) {
  .button {
    transition: none;
  }
}

Angular's native animate.enter and animate.leave

Since Angular 20.2 the framework can apply CSS classes while a node enters and leaves the DOM, and @angular/animations is deprecated in favour of it. For many apps this covers the common case: each element has its own self-contained enter or leave effect described in CSS. It needs no extra dependency, and you should prefer it when that is all you need.

<!-- Angular adds the class on enter and waits for the animation to finish before removing the node on leave. -->
@if (open()) {
<section animate.enter="panel-enter" animate.leave="panel-leave">Details</section>
}

What it does not give you is coordination: no built-in way to hold a parent until all children have finished leaving, to reverse a keyed list item that is re-added while it is exiting, to stagger by DOM order, or to animate between two states of one element when a signal changes.

Angular Movement

Movement earns its place when motion is driven by state and must be coordinated:

  • State to state — moveVariants and [moveAnimation] animate to a new target whenever a signal changes.
  • Presence — *movePresence and *movePresenceFor keep a view (or each keyed row) mounted until every leave animation finishes, including nested children and revival mid-exit.
  • Orchestration — moveStagger and variant staggerChildren for DOM-order delays.
  • Interaction feedback — moveWhileHover, moveWhileTap and moveWhileFocus, with proper touch semantics.
  • Scroll, springs, SVG and signals — moveScroll, moveSpringValue, movePathDraw and moveTransform.
  • Imperative sequences — MoveAnimator, with automatic reduced-motion handling and SSR no-ops.
<ul>
  <li
    *movePresenceFor="let item of items(); trackBy: byId"
    move="fade-up"
    [moveWhileHover]="{ y: [0, -2] }"
  >
    {{ item.label }}
  </li>
</ul>

Raw WAAPI

element.animate() is fine for one isolated effect. You then own reduced motion, cancellation, committing final styles and server-side no-ops. Movement's engines and MoveAnimator are thin wrappers that do these things consistently.

Honest trade-offs

Warning

Movement plays on the Web Animations API, which depends on hydration: anything it animates in from a hidden state needs the app to have started. For above-the-fold entrances that must paint immediately, prefer CSS. See Accessibility and troubleshooting.

  • It is an additional dependency (a small, tree-shakeable one). If CSS or native enter and leave cover your needs, you do not need it.
  • Layout, drag and smooth-scroll APIs are still experimental. Prefer native scrolling.

Next

Choose an API inside Movement, or migrate from @angular/animations.