DEV Community

AlbertMarashi for Promatia

Posted on

Svelte loading state indicator (promises)

Web apps often require loading state (things like loading spinners) to let a user know that an operation is taking place. These operations often take time, so it's best to let the user know something is loading, which helps improve UX and prevents form resubmissions and etc.

We are using this in Promatia and PromaTimes svelte rebuilds.

Add Loading State Indicators to Svelte

REPL: https://svelte.dev/repl/4fefb61253aa4c26b26485e0b2b8c06c?version=3

Imagine you have some UI where a button triggers an async function, and you'd like to display a loading indicator

<script>

async function login(){
  await new Promise(resolve => setTimeout(resolve, 2000) //wait for 2 seconds
}
</script>
<form>
  <button on:click="login">Do thing</button>
</form>

Create an overlay loading indicator

Displays a translucent scrim, with a text loading indicator that goes from . to ...

<div class="LoadingIndicator">
    {text}
</div>
<script>
import { onMount } from 'svelte'
let text = ''

async function loop(){
    if(text.length === 3) text = ''
    text += '.'
    await new Promise(resolve => setTimeout(resolve, 300))
    loop()
}

onMount(()=>{
    loop()
})

</script>
<style>

.LoadingIndicator {
    display: flex;
    background: rgba(0,0,0,0.2);
    justify-content: center;
    align-items: center;
    text-align: center;
    position: absolute; // overlays on top of parent element, parent must have display: relative;
    top: 0;
    bottom: 0;
    right: 0;
    left: 0;
    z-index: 20;
    font-size: 60px;
}
</style>

Create promiser.js

export default async (promise, subscriber)=>{
    subscriber(true)
    try {
        await promise
    } catch (err) {}
    subscriber(false)
}

Update your form

<script>
import promiser from './promiser.js'
import LoadingIndicator from './LoadingIndicator.svelte'
let loading = false

async function login(){
    return await new Promise(resolve => setTimeout(resolve, 3000))
}

</script>
<div class="form">
    <button on:click={()=>promiser(login(), status => loading = status)}>
        Click me
    </button>
    {#if loading}
    <LoadingIndicator/>
    {/if}
</div>
<style>

    .form {
        position: relative;
        padding: 20px;
    }

</style>

View the REPL: https://svelte.dev/repl/4fefb61253aa4c26b26485e0b2b8c06c?version=3.22.2

Top comments (0)