Add a YouTube-like Page Loading Animation in SvelteKit

We’ve all seen it. A colored sliver at the top that indicates a page loading in modern websites. YouTube is an excellent example of this. While there might be libraries to do this with NextJS and other frameworks, I have yet to see one that does it for…


This content originally appeared on DEV Community and was authored by Shajid Hasan

We've all seen it. A colored sliver at the top that indicates a page loading in modern websites. YouTube is an excellent example of this. While there might be libraries to do this with NextJS and other frameworks, I have yet to see one that does it for SvelteKit. But fortunately, it isn't so hard to implement yourself! If you're interested in only the code, here's the GitHub repository.

Introduction

Hello there! Welcome to my first blog post ever for developers(for anyone, actually). If you still haven't got a clear picture of what we're going to do, here's a GIF for you:
GIF demo
You can click here for a demo as well. In SvelteKit, you can have a load function that will run on the server/client before a page is loaded. While the load function does its job, our page loading bar on top will continue to increase for a nice visual feedback. It's awesome!

How

Before we get down to write some code, let me quickly explain how it'll work. I will assume you have at least some experience with Svelte, Svelte's stores and SvelteKit.
We'll have a PageLoader.svelte component. It starts animating right from the time it's mounted(which is when a user clicks a link). Its width starts to go from 0 to 70%. And as soon as the next page is done loading, it'll quickly animate to 100%, and then disappear nicely. We'll know when navigation is started and ended with SvelteKit's sveltekit:navigation-start and sveltekit:navigation-end window events. We'll keep this navigation state data in a Svelte writable store so that we can control PageLoader.svelte component's animation.
That's about it! If this sounds simple enough, go ahead and give this a try!

Setup

You will most likely do this in an existing project of yours. But for the sake of this tutorial, let me scaffold a new SvelteKit project with npm init svelte@next. I will enable TypeScript for this example. After installing the required packages with npm install, I'll create some files. Here's the directory structure we'll have after that:

src
└───routes
|   |   __layout.svelte
|   |   page-1.svelte
|   |   page-2.svelte
|   |   index.svelte
|   |
└───components
|   |   PageLoader.svelte
|   |
└───stores
|   |   navigationState.ts
|   |
└───styles
|   |   global.css

Pretty simple, right? I'll add some styling to the global.css file. I could do that in the Svelte components, but this is a tiny project with shared styles across the pages. You can refer to the GitHub repository of this tutorial if you want the code.
Now it's time to create the pages. I'll just link the page-1.svelte and page-2.svelte using anchor tags inside the index.svelte. Here's the code for these three:

<!-- routes/index.svelte -->

<div class="container">
    <div class="content">
        <h1>Page loading progress bar in action with SvelteKit.</h1>

        <div class="links">
            <a href="/page-1">Page 1</a>
            <a href="/page-2">Page 2</a>
        </div>
    </div>
</div>
<!-- routes/page-1.svelte -->

<div class="container">
    <div class="content">
        <h1>You're on Page 1.</h1>
        <div class="links">
            <a href="/">Home</a>
            <a href="/page-2">Page 2</a>
        </div>
    </div>
</div>
<!-- routes/page-2.svelte -->

<div class="container">
    <div class="content">
        <h1>You're on Page 2.</h1>
        <div class="links">
            <a href="/">Home</a>
            <a href="/page-1">Page 1</a>
        </div>
    </div>
</div>

Nothing too fancy. Now let's move on to the code that's actually relevant.

Let's do this

We'll go to the routes/__layout.svelte file. All the pages will be rendered inside this layout file, so we'll have to add a slot so that other pages have a place. We'll also import the global.css here.

<!-- routes/__layout.svelte -->

<script lang="ts">
  import '../styles/global.css';
</script>

<slot></slot>

At this point you can run npm run dev to see if everything's working properly.

Svelte has a special element called <svelte:window>. You can easily add window event listeners with this element. Upon inspecting the docs, I've come to know SvelteKit emits sveltekit:navigation-start and sveltekit-navigation-end window events. Let's just grab them.

<!-- routes/__layout.svelte -->

<script lang="ts">
    import '../styles/global.css';
</script>

<svelte:window
    on:sveltekit:navigation-start={() => {
        console.log('Navigation started!');
    }}
    on:sveltekit:navigation-end={() => {
        console.log('Navigation ended!');
    }}
/>

<slot></slot>

Now open up the browser's console, and see if you get the navigation messages properly. All's good on my side so let's go ahead and create the stores/navigationState.ts file.

// stores/navigationState.ts

import { writable } from 'svelte/store';

type NavigationState = "loading" | "loaded" | null;

export default writable<NavigationState>(null);

Now we have a way to know the navigation state from anywhere within the app. We haven't edited the event listeners for this yet, but we'll get to that.

Before doing anything else, let's create the components/PageLoader.svelte component. Let's write the markup first.

<!-- components/PageLoader.svelte -->

<div class="progress-bar">
    <div class="progress-sliver" style={`--width: ${$progress * 100}%`} />
</div>

<style>
    .progress-bar {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        height: 0.5rem;
    }
    .progress-sliver {
        width: var(--width);
        background-color: #f8485e;
        height: 100%;
    }
</style>

As you can see, we're passing in a $progress * 100 variable into a CSS custom property with the style attribute. progress is going to be a Svelte tweened value.
Initially progress will be 0, and then as soon as the component is mounted, we'll animate it to 0.7 to go to 70%. We'll also listen for the navigationState change from the store we created earlier. When the state is 'loaded', we'll set the progress to 1 (100%). Here's full code:

<!-- components/PageLoader.svelte -->

<script>
    import { onDestroy, onMount } from 'svelte';
    import { tweened } from 'svelte/motion';
    import { cubicOut } from 'svelte/easing';
    import navigationState from '../stores/navigationState';

    const progress = tweened(0, {
        duration: 3500,
        easing: cubicOut
    });
    const unsubscribe = navigationState.subscribe((state) => {
        if (state === 'loaded') {
            progress.set(1, { duration: 1000 });
        }
    });
    onMount(() => {
        progress.set(0.7);
    });
    onDestroy(() => {
        unsubscribe();
    });
</script>


<div class="progress-bar">
    <div class="progress-sliver" style={`--width: ${$progress * 100}%`} />
</div>

<style>
    .progress-bar {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        height: 0.5rem;
    }
    .progress-sliver {
        width: var(--width);
        background-color: #f8485e;
        height: 100%;
    }
</style>

As you can see, we did not forget to unsubscribe the store when the component is destroyed. Also, notice the duration. When we're animating from 0 to 70%, we'll go a bit slow. When the page is loaded, we'll go to 100% much faster.
Now there's only one thing left to do. Let's go back to routes/__layout.svelte file. We'll change the event listeners so that they can set the navigationState when navigation is occurring. We're going to import the PageLoader.svelte component here, and show it only when navigationState is equal to 'loading'. We'll bring in Svelte's fade transition as well to make the PageLoader component fade out once a page is loaded. But remember, we'll have to add some delay to it so that the progress bar reaches 100% before it disappears. Take a look at the code now:

<!-- routes/__layout.svelte -->

<script lang="ts">
    import { fade } from 'svelte/transition';

    import navigationState from '../stores/navigationState';
    import PageLoader from '../components/PageLoader.svelte';
    import '../styles/global.css';
</script>

<svelte:window
    on:sveltekit:navigation-start={() => {
        $navigationState = 'loading';
    }}
    on:sveltekit:navigation-end={() => {
        $navigationState = 'loaded';
    }}
/>
{#if $navigationState === 'loading'}
    <div out:fade={{ delay: 500 }}>
        <PageLoader />
    </div>
{/if}

<slot />

That's it, folks!

Your page loading animation is ready now. Restart the dev server and check if it works properly.

Conclusion

For my first post ever, I hope that was okay! Check out the GitHub repository if you still have any doubts. I understand this might not be the best way to do this, but it'll work fine for most cases. Feel free to leave any feedback/comments/questions.


This content originally appeared on DEV Community and was authored by Shajid Hasan


Print Share Comment Cite Upload Translate Updates
APA

Shajid Hasan | Sciencx (2021-08-20T09:11:55+00:00) Add a YouTube-like Page Loading Animation in SvelteKit. Retrieved from https://www.scien.cx/2021/08/20/add-a-youtube-like-page-loading-animation-in-sveltekit/

MLA
" » Add a YouTube-like Page Loading Animation in SvelteKit." Shajid Hasan | Sciencx - Friday August 20, 2021, https://www.scien.cx/2021/08/20/add-a-youtube-like-page-loading-animation-in-sveltekit/
HARVARD
Shajid Hasan | Sciencx Friday August 20, 2021 » Add a YouTube-like Page Loading Animation in SvelteKit., viewed ,<https://www.scien.cx/2021/08/20/add-a-youtube-like-page-loading-animation-in-sveltekit/>
VANCOUVER
Shajid Hasan | Sciencx - » Add a YouTube-like Page Loading Animation in SvelteKit. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/08/20/add-a-youtube-like-page-loading-animation-in-sveltekit/
CHICAGO
" » Add a YouTube-like Page Loading Animation in SvelteKit." Shajid Hasan | Sciencx - Accessed . https://www.scien.cx/2021/08/20/add-a-youtube-like-page-loading-animation-in-sveltekit/
IEEE
" » Add a YouTube-like Page Loading Animation in SvelteKit." Shajid Hasan | Sciencx [Online]. Available: https://www.scien.cx/2021/08/20/add-a-youtube-like-page-loading-animation-in-sveltekit/. [Accessed: ]
rf:citation
» Add a YouTube-like Page Loading Animation in SvelteKit | Shajid Hasan | Sciencx | https://www.scien.cx/2021/08/20/add-a-youtube-like-page-loading-animation-in-sveltekit/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.