DEV Community

Cover image for Using the View Transition API on Angular Framework
Diogo Machado
Diogo Machado

Posted on

Using the View Transition API on Angular Framework

Recently the framework Angular launched exiciting features in the V17 version, in this article we will learn how to start using the View Transition API. This feature does not have good documentation, the idea here is to explain in practice.

In the demo project, we simulate a list of products, and when the user selects one, the application opens a new route with a smooth transition.

The View Transitions API is still experimental in both (browsers and Angular), you can check the actual support here https://caniuse.com/view-transitions.

Without View Transition enabled

Interface working without the transition

Enabling View Transition with Angular

The first thing you need to do is to include the withViewTransitions() along with the proviceRouter.



const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'product/:id', component: ProductComponent },
];

bootstrapApplication(App, {
  providers: [provideRouter(routes, withViewTransitions())],
});


Enter fullscreen mode Exit fullscreen mode

With default View Transition effect

Interface working with the API enabled

Customizing the default animation



@keyframes fade-in {
  from {
    opacity: 0;
  }
}

@keyframes fade-out {
  to {
    opacity: 0;
  }
}

::view-transition-old(root) {
  animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out;
}

::view-transition-new(root) {
  animation: 2s cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in;
}


Enter fullscreen mode Exit fullscreen mode

Animating isolated elements

Is important that each element have a unique name, in a @for example, if you set the same name for each element in the loop, the view transition will not work.


 html
<h1>Products</h1>
<div class="grid">
  @for(product of products; track product.id) {
  <a
    routerLink="product/coffee-65324"
    (mouseenter)="setCurrentId(product.id)"
    class="card"
  >
    <header>
      <img
        [style.view-transition-name]="returnViewTransition(product.id)"
        src="https://picsum.photos/id/63/367/267"
      />
    </header>

    <div class="content">
      <h2 class="card__title">{{ product.name }}</h2>
      <p class="card__price">$3</p>
    </div>
  </a>
  }
</div>


Enter fullscreen mode Exit fullscreen mode

In the path "/", our list have a loop of products, in each item, we will add:


 html
 <img
   [style.view-transition-name]="returnViewTransition(product.id)"
   src="https://picsum.photos/id/63/367/267"
 />


Enter fullscreen mode Exit fullscreen mode

As mentioned, we need to respect that only one element will have the property view-transition-name: banner, this little method will ensure to return it at the right moment. My strategy here was:

  • Create a small service inject root with a parameter signal to store the current id that the user is navigating with the cursor.
  • returnViewTransition will return dinamic based on the comparison of the product id in the loop and the current id in the signal.

Inside the /product/:id route, we have this block:


 html
<header class="hero">
  <img src="https://picsum.photos/id/63/1280/720" />
  <button class="close-btn" routerLink="/">Back</button>
</header>


Enter fullscreen mode Exit fullscreen mode

Now we need to tell the browser the view-transition-name associated with the home image:


css
.hero img {
width: 100%;
view-transition-name: banner;
}
Enter fullscreen mode Exit fullscreen mode




Final result

Interface with all customizations


Demo project

https://stackblitz.com/edit/stackblitz-starters-ba6uus?file=src%2Fpages%2Fhome%2Fhome.component.html


References

  1. https://developer.chrome.com/docs/web-platform/view-transitions/
  2. https://angular.dev/guide/signals#writable-signals
  3. https://blog.angular.io/check-out-angulars-support-for-the-view-transitions-api-3937376cfc19

Top comments (0)