Monthly Archives: September 2022

Creating a callable Toast component in Svelte using bind:this (DaisyUI optional)

I’m using Svelte+Kit for new development, and also starting to use DaisyUI, i found a need to use the Toast component to show a message which appears for a while, then disappears, such as an error message on a form submit, or a success message.

Creating a Svelte component called Toast.svelte would be easy. The challenge is to wrap a callable function to invoke the functionality which would:

  • make the Toast visible
  • set the message, and the alert style (success, error, etc)
  • allow it to disappear after X seconds automatically

To start, i made the simple component, which would have an exported message and alerttype props.

<script lang="ts">
export let message = '';
export let alerttype = 'alert-error';
</script>

<div class="toast toast-top toast-start z-40">
    {#if message}
    <div class="alert {alerttype}">
        <div>
            <span>{message}</span>
        </div>
    </div>
    {/if}
</div>

That allowed me to invoke the Toast from the parent +page.svelte like so:

<script lang="ts">
export let toastMessage = 'some error message';
export let toastAlertType = 'alert-error';
</script>

<Toast message={toastMessage} alerttype={toastAlertType} />

Then i could write a page-level function callToast(), or even a *.ts library, but that was too messy. I want the callable function withing the same Toast.svelte component file.

I did it using the Svelte bind:this element directive.

./components/Toast.svelte

<script lang="ts">
let message = '';
let alerttype = 'alert-error';

// https://akashmittal.com/svelte-calling-function-child-parent/
// call from parent as: 
// let toast: Toast;
// toast.callToast(message, alerttype);
// <Toast bind:this={toast} />

export function callToast(msg: string, type?: string|undefined, ms?: number|undefined) {
    console.log('callToast()');
    let milliseconds: number = 8000;
    if(ms) { milliseconds = ms; }
    if(type) { alerttype = `alert-${type}`; }
    message = msg;

    setTimeout(() => {
        message = '';
    }, milliseconds);
}

</script>

<div class="toast toast-top toast-start z-40">
    {#if message}
    <div class="alert {alerttype}">
        <div>
            <span>{message}</span>
        </div>
    </div>
    {/if}
</div>

+page.svelte:

<script lang="ts">
    import Toast from "$components/Toast.svelte";
    let toast: Toast;
</script>

<Toast bind:this={toast} />

<button on:click={() => toast.callToast('testing this toast notification...', 'error')} class="btn">toast test</button>

Depending on your coding style, this may be easier than using a third-party library.

References:

https://akashmittal.com/svelte-calling-function-child-parent/

Tan Li Hau – Svelte Tutorial for Beginners – bind:this