You can animate an App Router page without turning the page or layout into a Client Component. Keep data fetching and page composition in Server Components, use CSS for straightforward visual effects, and isolate any state, event handlers, effects, or browser APIs in the smallest client-side component that needs them. For route transitions, check your installed React and Next.js versions before relying on the newer View Transition APIs.
Why an animation does not automatically require a client page
In the Next.js App Router, pages and layouts are Server Components by default. A Server Component can render HTML that CSS animates; the browser does not need React state or event handlers just to apply a transition or keyframe animation. A client boundary is needed when the animation depends on client-side behavior such as state, event handlers, effects, browser APIs, or custom hooks. Next.js recommends marking specific interactive components rather than large parts of the interface as client-side code. Next.js explains the Server and Client Component model and its module boundaries.
Choose the smallest tool that fits the effect
| Approach | Best for | What to know |
|---|---|---|
| CSS transitions and keyframes | Hover and focus effects, decorative movement, and simple entrances | Can animate rendered content without adding a client component for the animation itself. Include a reduced-motion path for people who request less movement. See MDN’s prefers-reduced-motion reference. |
| React and Next.js View Transitions | Shared-element effects, route changes, crossfades, and Suspense reveals | The current Next.js guide describes APIs included in React 19.3. Whether an animation runs depends on the kind of transition and browser support; unsupported browsers still display the content. The guide is in Next.js’s canary documentation and can change. See the Next.js View Transitions guide and React’s React 19.3 announcement. |
| Motion for React | More involved component animation, layout animation, and viewport-triggered effects | Motion documents an RSC-oriented component entry point, but that does not make stateful or browser-dependent behavior server-side. See Motion’s component documentation. |
Keep a page server-rendered and isolate interactive behavior
Leave page.tsx or layout.tsx as a Server Component when it handles data fetching and page composition. Put an animation controller in a separate file only when it needs client-side state or events.
Example: a client-side toggle around server-rendered content
The server page can render the content and pass it through a small client component as children. The fact that server-rendered content appears inside a client component’s slot does not, by itself, pull that content into the client module graph. Next.js documents this server/client interleaving pattern in its Server and Client Components guide.
Recommended Free Tools
#1 Best Overall
For example, the server page can provide the content:
// app/page.tsx — Server Component
import Reveal from './reveal';
export default async function Page() {
const item = await getItem();
return (
<Reveal>
<article>
<h1>{item.title}</h1>
<p>{item.description}</p>
</article>
</Reveal>
);
}
The small client component can own the button and visibility state:
Rank #2
// app/reveal.tsx
'use client';
import { useState } from 'react';
export default function Reveal({ children }: { children: React.ReactNode }) {
const [shown, setShown] = useState(true);
return (
<section>
<button onClick={() => setShown((value) => !value)}>
Toggle content
</button>
<div className={shown ? 'content shown' : 'content hidden'}>
{children}
</div>
</section>
);
}
Here the click handler and state require a client boundary; the data fetching and article markup do not. A CSS class can handle the visual transition:
/* app/globals.css */
.content {
opacity: 1;
transition: opacity 200ms ease;
}
.content.hidden {
opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
.content {
transition: none;
}
}
This example fades the content but leaves it in the layout and potentially available to interaction while transparent. If the hidden state must remove content from layout or prevent interaction, choose an appropriate visibility or rendering strategy rather than relying on opacity alone.
Rank #3
Use Motion in an RSC context without confusing rendering and behavior
Motion documents this component import for React Server Component contexts such as Next.js:
import * as motion from 'motion/react-client';
That entry point is for Motion components. It is not a promise that all animation logic can run on the server: if an effect needs hooks, events, or browser APIs, put that behavior behind a suitable client boundary. Start with Motion’s documented import and add a client wrapper only for the specific interactive behavior your component needs.
What to check before adding route transitions
Route and shared-element transitions have more constraints than a CSS hover effect. The current Next.js guide says the relevant React APIs are included in React 19.3 and that App Router support works without additional configuration. Because that guide is in the canary documentation tree, verify it against the versions installed in your project rather than assuming every released Next.js and React combination supports the same APIs.
Animation activation also depends on how an update occurs. React says View Transition animations are driven by qualifying transitions, Suspense reveals, and useDeferredValue; an ordinary urgent state update does not trigger one. The React 19.3 announcement explains that updates not marked as transitions remain immediate instead of triggering these animations.
Browser support is another variable. The current Next.js guide describes newer features as available in Chromium 125 and later and recent Safari and Firefox versions, with some Safari behavior differences. If a browser lacks the required API, the page content still works, but the transition does not animate. Test the browsers your project supports and treat the transition as progressive enhancement.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Respect reduced-motion preferences
Nonessential movement should have a reduced-motion alternative. Use the CSS prefers-reduced-motion media feature to remove or tone down transitions and keyframes when a visitor has requested less motion. MDN documents the media feature and its use in CSS at its prefers-reduced-motion reference. For JavaScript-driven effects, provide an equivalent behavior rather than assuming that a CSS rule alone controls every animation system.
Quick Recap
A practical decision path
- Does CSS alone produce the effect? Keep the page server-rendered and use CSS transitions or keyframes.
- Does a specific control need to start, stop, or configure the animation? Put that state and its event handlers in a small component marked
'use client'; keep surrounding page content server-rendered. - Does the effect span routes or animate shared elements? Check your installed React and Next.js versions against the current View Transitions guide, then confirm behavior in target browsers.
- Do you need more component-level animation features? Consider Motion’s
motion/react-cliententry point for RSC contexts, while isolating any browser-dependent interaction appropriately. - For each approach, what happens with reduced motion? Provide a less-motion path for nonessential movement.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

