DEV Community

Evan Winter
Evan Winter

Posted on • Updated on

Simple Page Transitions with SvelteKit

Demo: https://sveltekit-page-transitions.netlify.app/
Source code: https://github.com/evanwinter/sveltekit-page-transitions

Overview

  1. Create a <PageTransition /> component that does a simple fade-out-and-in transition (using Svelte's built-in transition directive) when a given prop changes.

  2. Create a layout file, wrap its content with the <PageTransition /> component, and pass the current page's path to the component as a prop.

Step 1: Creating the <PageTransition /> component

Create a component file at src/lib/components/PageTransition.svelte.

Import the fly transition from Svelte's built-in transition library, and setup an element that flys in and out. Add a delay to the in transition that's equal to or greater than the duration of the out transition (otherwise, the user will see them happen at the same time).

Export a variable called refresh and wrap the element inside of a #{key ...} block.

The contents of the block will be destroyed and recreated only when the value of refresh changes.

When that happens, the out transition will be executed immediately, and the in transition happen once the out transition finishes –– creating a "fade-out-and-back-in" effect.

<!-- PageTransition.svelte -->
<script>
  import { fly } from "svelte/transition"
  export let refresh = ""
</script>

{#key refresh}
  <div in:fly={{  x:-5, duration: 500, delay: 500 }}
       out:fly={{ x: 5, duration: 500             }}>
    <slot />
  </div>
{/key}
Enter fullscreen mode Exit fullscreen mode

Step 2: Using the <PageTransition /> component

Create a layout file at src/routes/__layout.svelte.

<!-- __layout.svelte -->
<script>
  import PageTransition from "$lib/components/PageTransition.svelte"
  export let key
</script>

<!-- 1. Assign current route's path to `key` prop -->
<script context="module">
  export const load = async ({ page }) => ({
    props: {
      key: page.path,
    },
  })
</script>

<div>
  <nav>
    <a href="/">Home</a>
    <a href="/about">About</a>
  </nav>

  <!-- 2. Pass `key` prop to the component so it knows when to transition -->
  <PageTransition refresh={key}>
    <slot />
  </PageTransition>
</div>
Enter fullscreen mode Exit fullscreen mode

The load function runs before the layout component is created or updated. It provides access to data about the current page, including the path of the page.

We store the path of the current page in a variable, key, and pass it to the PageTransition component as the refresh prop.

The PageTransition component will then destroy and recreate itself (transitioning out and back in) only when the user navigates to a new page.

Discussion (9)

Collapse
felixbaumgaertner profile image
felixbaumgaertner

Thanks for this nice tutorial!
It seems like the variable names have changed, so that "export const load = async ({ page })" has to be changed to "export const load = async ({ url })". Don't forget the props: "key: page.path" to "key: url"

Collapse
evanwinter profile image
Evan Winter Author

Ah, thanks, I hadn't seen that! I'll update this post to reflect those changes

Collapse
tonborzenko profile image
Anton Borzenko • Edited on

Thank you for great job. Is it possible to use import { page } from '$app/stores', how do you think? I tried to use $page.path as a key, but it has a bug in animation between components...

Collapse
evanwinter profile image
Evan Winter Author • Edited on

What kind of bug? Is it changing to the next route before it finishes the "out" transition of the previous route?

If so... and I'm not sure I'll word this right... but essentially, I think the issue is that the $page.path variable is reactive and updates immediately when you navigate to the next route, irrespective of which render instance of the component it started with. With the approach shown in the post, we store a reference to the previous route that's scoped to the particular render instance, so PageTransition.svelte doesn't see a new key until after the first route has transitioned out (destroyed itself) – then, prior to transitioning back in (recreating itself), it loads the new key for the new route.

Collapse
darkeye123 profile image
Matej Leško

Thank you for this, I approached this by using $page store directly but basically new page didn't occur, I just saw transition out. This could explain the behavior

Collapse
glassforms profile image
Robert Stewart

Have you ever tried this approach using a fixed navigation? In all of the demos I've seen, when you click on a link, the site jumps you to the top of the page before transitioning the page out. Do you know why this happens, and how to prevent it?

Collapse
nipodemos profile image
Nipodemos

thank you very much for this post, simple and functional

Collapse
evanwinter profile image
Evan Winter Author • Edited on

My pleasure! Glad it was helpful.

Collapse
ohaleks profile image
Aleksander Brymora

Perfectly done! And worked the first time!
Thanks for sharing