Easy-Peasy Page Transitions in SvelteKit 🎨✨

Learn how to spice up your SvelteKit app with slick page transitions using Svelte’s built-in transition and animation magic. Boost that user experience with eye-catching visuals between pages. 🚀

Easy-Peasy Page Transitions in SvelteKit 🎨✨
M
Muhammad Surya J

Overview 🌟

In today’s modern web scene, smooth page transitions can seriously level up your user experience. Lucky for us, SvelteKit makes it super easy to pull this off thanks to Svelte’s powerful built-in animation and transition APIs. In this guide, we’re gonna break down how to add buttery-smooth page transitions to your SvelteKit app. Let’s roll! 🎉

Prerequisites 🛠️

Before diving in, make sure you’ve got the following under your belt:

  • Basic knowledge of Svelte and SvelteKit.
  • A working SvelteKit project. If not, no worries — just spin one up like this:
    npx sv create my-sveltekit-app
    cd my-sveltekit-app
    npm install
    npm run dev

Step 1: Install What’s Needed 📦

We’re keeping it lean — no extra packages here. We’ll be using svelte/transition and svelte/easing, which come out of the box with Svelte. Easy win.

Step 2: Set Up a Layout Component 🏗️

To get transitions going across all pages, we’ll tweak the +layout.svelte file — this is basically the wrapper for all your routes.

  1. Open or create src/routes/+layout.svelte.
  2. Throw in the following code to wire up the layout with a transition:
<script>
	import { fade } from 'svelte/transition';
	let { children, data } = $props();
	let { pathname } = $derived(data);
</script>

{#key pathname}
	<div transition:fade>
		{@render children()}
	</div>
{/key}

What’s Happening:

  • transition:fade: Applies a fade effect when switching pages.
  • {@render children()}: This is where the current page content gets rendered.

But hang tight — we need pathname to make this work. Time to bring in the load function.

Step 3: Grab the Pathname Using load 🔄

The load function is where we can fetch info about the current URL. We’ll use it to get the pathname and pass it into our layout.

  1. Create a new file at src/routes/+layout.ts:
export const load: LayoutLoad = async ({ url }) => {
	const { pathname } = url;

	return {
		pathname
	};
};
  1. Use pathname in your +layout.svelte:
<script>
	import { fade } from 'svelte/transition';
	let { children, data } = $props();
	let { pathname } = $derived(data);
</script>

{#key pathname}
	<div in:fade={{ duration: 300, delay: 400 }} out:fade={{ duration: 300 }}>
		{@render children()}
	</div>
{/key}

What’s Going On:

  • in:fade and out:fade: Sets up enter and exit animations with custom timing.
  • delay: Adds a small pause for that smooth handoff between pages.

Step 4: Make It Pop with Easing 🎢

Want your transitions to feel a bit more alive? Add some easing curves. Svelte’s got your back with a bunch of built-in options.

  1. Import easing from svelte/easing:
<script>
	import { fade } from 'svelte/transition';
	import { cubicIn, cubicOut } from 'svelte/easing';
	let { children, data } = $props();
	let { pathname } = $derived(data);
</script>

{#key pathname}
	<div
		in:fade={{ easing: cubicOut, duration: 300, delay: 400 }}
		out:fade={{ easing: cubicIn, duration: 300 }}
	>
		{@render children()}
	</div>
{/key}

What’s the Deal:

  • cubicIn and cubicOut: These easing curves give your transitions a more natural feel.

Step 5: Try Out the fly Effect ✈️

Feeling fancy? Swap fade with fly to add motion to your page transitions.

<script>
	import { fly } from 'svelte/transition';
	import { cubicIn, cubicOut } from 'svelte/easing';
	let { children, data } = $props();
	let { pathname } = $derived(data);
</script>

{#key pathname}
	<div
		in:fly={{ easing: cubicOut, y: 10, duration: 300, delay: 400 }}
		out:fly={{ easing: cubicIn, y: -10, duration: 300 }}
	>
		{@render children()}
	</div>
{/key}

What’s What:

  • y: 10 and y: -10: Controls the direction of the fly animation (up or down).

Optional: Add a Loading Bar ⏳

For that extra polish, show a loader while the next page is loading. Super handy if your routes are doing any data-fetching or just need a sec.

<script>
	import { beforeNavigate, afterNavigate } from '$app/navigation';

	let isLoading = $state(false);
	let loadingProgress = $state(0);
	let loadingInterval: ReturnType<typeof setInterval> | null = null;

	beforeNavigate(({ to }) => {
		if (to?.route.id) {
			isLoading = true;
			loadingProgress = 0;

			loadingInterval = setInterval(() => {
				loadingProgress = Math.min(90, loadingProgress + 5);
			}, 100);
		}
	});

	afterNavigate(() => {
		if (loadingInterval) {
			clearInterval(loadingInterval);
			loadingInterval = null;
		}

		loadingProgress = 100;

		setTimeout(() => {
			isLoading = false;
		}, 300);
	});
</script>

{#if isLoading}
	<div class="absolute inset-x-0 top-0 z-10">
		<div class="h-1 w-full bg-slate-200 dark:bg-slate-700">
			<div
				class="h-full animate-pulse bg-slate-700 transition-all duration-300 dark:bg-slate-400"
				style="width: {loadingProgress}%"
			></div>
		</div>
	</div>
{/if}

What’s Up Here:

  • beforeNavigate and afterNavigate: Used to toggle a loading state during navigation.

Bonus Info: This Website Uses It Too 🌐

Yep, the website you’re reading this on? It uses the same kind of page transitions we’re talking about here. A loading bar while pages change, so users always know something’s happening behind the scenes.

Wrapping It Up 🎯

Adding smooth page transitions to your SvelteKit app is a dead-simple way to bump up the UX and make your app feel way more pro. Thanks to Svelte’s built-in transition and animation tools, it’s super quick to get started. Try out different effects, tweak some timings, and make your app really stand out. 🚀

Happy coding, and may your transitions be silky-smooth and jaw-dropping! ✨🎉