Animating Elements on the Same Page using @view-transition in a Next.js 14 Application

Fri Oct 11 2024

Overview

This guide details how to animate elements within the same route or page in a Next.js 14 application using the @view-transition API. By animating elements on the same page, you can provide a smoother and more engaging user experience when content is updated or elements are manipulated.

Prerequisites

Before you get started, ensure the following prerequisites are met:

  • Familiarity with Next.js 14 and React.
  • Basic understanding of modern JavaScript and CSS animations.
  • A Next.js 14 application set up and running locally.

Getting Started with @view-transition for Same-Page Animations

The @view-transition API is typically used for transitioning between pages, but it can also be leveraged to animate elements within the same page. This is particularly useful for cases where you want to update or replace parts of the page's content while maintaining a fluid, visually appealing user experience.

1. Triggering Element Transitions

Below is an example of how to create a color filter that triggers element transitions on the same page:

"use client";

import React, { useState, useEffect } from "react";

interface Item {
  id: string;
  name: string;
  color: string;
}

interface Props {
  items: Item[];
  selectedFilter: string | null;
}

const FilteredItems = ({ items, selectedFilter }: Props) => {
  useEffect(() => {
    const elements = document.querySelectorAll(".item");

    document.startViewTransition(() => {
      elements.forEach((element) => {
        const itemId = element.getAttribute("data-item");
        if (selectedFilter === null || selectedFilter === itemId) {
          element.classList.remove("hidden");
        } else {
          element.classList.add("hidden");
        }
      });
    });
  }, [selectedFilter]);

  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mt-4">
      {items.map((item) => (
        <div
          key={item.id}
          data-item={item.id}
          className="item transition-all duration-300 ease-in-out p-4 bg-white shadow-lg rounded-lg flex flex-col items-center justify-center"
          style={{ viewTransitionName: `item-${item.id}` }}
        >
          <div
            className="w-20 h-20 mb-2 rounded-md"
            style={{ backgroundColor: item.color }}
          ></div>
          <h3 className="text-lg font-semibold">{item.name}</h3>
        </div>
      ))}
    </div>
  );
};

export default FilteredItems;

In this example, document.startViewTransition() is used to apply transitions when the filter is updated. Each item is assigned a unique viewTransitionName to ensure that the transitions track and animate the elements smoothly when their visibility changes.

2. Adding Custom Animations

To further enhance the animations, you can use the ::view-transition-group pseudo-element. For example, to apply custom styles to all elements during the transition, use:

::view-transition-group(*) {
  animation-duration: 0.9s;
}

This applies a 0.9s animation to all items during the transition. You can also target specific animations using viewTransitionName if needed.

Conclusion

The @view-transition API is a powerful tool for animating elements within the same page, allowing for seamless and engaging user experiences. By using JavaScript to trigger transitions and CSS to style them, you can significantly improve the visual quality of interactions in your Next.js 14 application.

Instead of relying on conditional rendering, modifying styles while leveraging view transitions provides a smoother and more appealing way to filter and animate elements. This approach enhances the overall experience, making animations feel polished and natural.

Be sure to consider fallback options for browsers that don't support the @view-transition API and ensure your animations are both visually appealing and performant.

Further Reading

For more information, refer to the MDN documentation on the View-Transition API.