Getting Started
What is Flyva?
Flyva is a small library for creating smooth, animated page transitions in Next.js and Nuxt applications. Instead of letting the browser hard-reload between pages, Flyva intercepts navigation, runs your leave animation, swaps the content, then runs your enter animation.
Inspired by Barba and Swup, it brings you elastic tools to orchestrate content-aware transitions that you always wished to do but framework's APIs were not prepared for.
It doesn't ship any animations itself - you bring your own using any JS animation library (anime.js, GSAP, Motion, etc.) or plain CSS. Flyva handles the orchestration and framework plumbing.
Ultimate use case
The idea for Flyva came from our daily work in a creative web development team. If you build apps and complex systems, you're probably already happy with Vue's <Transition> goodness or with using Motion to smoothly show or hide components. But if you use Next or Nuxt for creative dev work on highly animated websites, you're here for a reason - and you already know the pain points we're trying to solve. Fasten your seatbelts, and let's take you on a journey!
How it works
When a user clicks a FlyvaLink:
- Intercept — the click is prevented; the URL and trigger element are captured
- Prepare — your transition snapshots any DOM state it needs (rects, refs, clones)
- Leave — the outgoing page animates out (or overlaps with navigation when
concurrent: true- see Next transition modes or Nuxt transition modes) - Navigate — the framework pushes the new route, the DOM updates
- Enter — the incoming page animates in
- Cleanup — the transition resets itself for the next run
This all happens through a PageTransition object - a class (or plain object) with lifecycle hooks that you implement:
prepare → beforeLeave → leave → afterLeave → beforeEnter → enter → afterEnter → cleanupEvery hook is optional. A minimal transition only needs leave and enter.
The transition lifecycle
| Hook | Async | When it runs |
|---|---|---|
prepare | yes | Before anything animates. Snapshot DOM rects, cache element refs, clone nodes. |
beforeLeave | no | Synchronous setup right before leave. Disable pointer events, add overlay classes. |
leave | yes | Animate the outgoing content. Awaited - navigation won't happen until this resolves. |
afterLeave | no | Synchronous teardown after leave. Clean up styles from the leave phase. |
beforeEnter | no | Synchronous setup before enter. Set initial styles on the incoming content (e.g. opacity: 0). |
enter | yes | Animate the incoming content. Awaited - the transition isn't "done" until this resolves. |
afterEnter | no | Final cleanup. Remove overlay classes, log analytics. |
cleanup | no | Called after afterEnter. Null out all cached references. |
Context object
Every lifecycle hook receives a PageTransitionContext:
interface PageTransitionContext {
name: string; // the transition key (e.g. "fadeTransition")
trigger: string | Element; // "internal" or the clicked DOM element
options: Record<string, any>;
el?: Element; // the trigger element (the FlyvaLink that was clicked)
current?: Element; // outgoing content root (when the adapter tracks it)
next?: Element; // incoming content root (after the swap)
viewTransition?: ViewTransition; // set when using the View Transitions API path
}options always contains fromHref and toHref (set automatically), plus anything you pass via flyvaOptions / :flyva-options on the link.
Use context.current and context.next in transitions marked concurrent: true (or when the framework has set them) instead of relying only on querySelector for the element that is actually being swapped.
Choosing Next.js or Nuxt
| Next.js | Nuxt | |
|---|---|---|
| Package | @flyva/next | @flyva/nuxt |
| Integration | React context provider (FlyvaRoot) | Nuxt module with auto-imports |
| Transition registration | Explicit map in a client component | Auto-discovered from a directory |
| Link component | FlyvaLink wraps next/link | FlyvaLink wraps NuxtLink |
| Shared element refs | useRefStack hook | useRefStack composable (auto-imported) |
| Content swap wiring | FlyvaTransitionWrapper around page output (App Router) | FlyvaPage instead of NuxtPage |
| View Transitions API | FlyvaRoot config.viewTransition | flyva.viewTransition in nuxt.config |
Install
pnpm add @flyva/next @flyva/sharedpnpm add @flyva/nuxt @flyva/sharedContinue with the Next.js guide or the Nuxt guide.