• Stars
    star
    262
  • Rank 156,136 (Top 4 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 2 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Send temporary data after redirect, usually from endpoints. Works with both SSR and client.

sveltekit-flash-message โšก

This is a Sveltekit library that passes temporary data to the next request, usually from form actions and endpoints. It's useful for displaying a success or failure message after a POST, which should not always be displayed at the form, rather as a message on the page that the request was redirected to.

Since it's a temporary message it's also known as a "flash message", especially known from PHP apps, since it's easy to add this functionality with PHP's built-in session handling. With SvelteKit it's a bit harder, but this library was made to alleviate that, encouraging well-behaved web apps that Redirects after Post.

Installation

npm i -D sveltekit-flash-message
pnpm i -D sveltekit-flash-message

How to use

1. Add the flash message to app.d.ts (Typescript only)

In src/app.d.ts, add the type for the flash message to App.PageData as an optional property called flash. It can be as simple as a string, or something more advanced. It has to be serializable though, so only JSON-friendly data structures. Here's an example:

src/app.d.ts

declare namespace App {
  interface PageData {
    flash?: { type: 'success' | 'error'; message: string };
  }
}

2. Wrap the load function of a top-level +layout or +page route

If you're not using any load functions, this is a simple step. Create a src/routes/+layout.server.ts file with the following content:

src/routes/+layout.server.ts

export { load } from 'sveltekit-flash-message/server';

But most likely you already have a top-level load function, in which case you can import loadFlash and wrap your load function with it:

src/routes/+layout.server.ts

import { loadFlash } from 'sveltekit-flash-message/server';

export const load = loadFlash(async (event) => {
  const data = { someOther: 'data' };
  return data;
});

3. Display the flash message

Import getFlash in a layout or page component to display the flash message. getFlash will return a store that you'll use to access the message:

src/routes/+layout.svelte

<script lang="ts">
  import { getFlash } from 'sveltekit-flash-message';
  import { page } from '$app/stores';

  const flash = getFlash(page);
</script>

{#if $flash}
  {@const bg = $flash.type == 'success' ? '#3D9970' : '#FF4136'}
  <div style:background-color={bg} class="flash">{$flash.message}</div>
{/if}

4. Send flash messages

Server-side

To send a flash message from the server, import redirect from sveltekit-flash-message/server and use it in load functions and form actions.

Note: With SvelteKit 2, you don't need to throw the redirect anymore, just call redirect.

import { redirect } from 'sveltekit-flash-message/server'

throw redirect(
  status: number,
  location: string,
  message: App.PageData['flash'],
  event: RequestEvent | Cookies
)

// Makes a 303 redirect
throw redirect(
  location: string,
  message: App.PageData['flash'],
  event: RequestEvent | Cookies
)

// Makes a 303 redirect to the current URL
throw redirect(
  message: App.PageData['flash'],
  event: RequestEvent | Cookies
)

// For compatibility, the sveltekit signature can also be used,
// which will send no flash message.
throw redirect(
  status: number,
  location: string,
)

Form action example

src/routes/todos/+page.server.ts

import { redirect } from 'sveltekit-flash-message/server';

export const actions = {
  default: async ({ request, locals, cookies }) => {
    const form = await request.formData();

    await api('POST', `/todos/${locals.userid}`, {
      text: form.get('text')
    });

    const message = { type: 'success', message: "That's the entrepreneur spirit!" } as const;
    throw redirect(message, cookies);
  }
};

Endpoint example

src/routes/todos/+server.ts

import type { RequestEvent } from '@sveltejs/kit';
import { redirect } from 'sveltekit-flash-message/server';

export const POST = async ({ cookies }) => {
  const message = { type: 'success', message: 'Endpoint POST successful!' } as const;
  throw redirect(303, '/', message, cookies);
};

Setting without redirecting

If you want to display a flash message without redirecting, as an error message when validation fails for example, you can use the setFlash function:

import { fail } from '@sveltejs/kit';
import { setFlash } from 'sveltekit-flash-message/server';

export const actions = {
  default: async (event) => {
    const form = await event.request.formData();

    if (!form.get('text')) {
      setFlash({ type: 'error', message: 'Please enter text.' }, event);
      return fail(400);
    }
  }
};

Client-side

If you want to update the flash message on the client, use getFlash in any component:

src/routes/some-route/+page.svelte

<script>
  import { getFlash } from 'sveltekit-flash-message';
  import { page } from '$app/stores';

  const flash = getFlash(page);

  function showMessage() {
    $flash = { type: 'success', message: 'Updated from other component!' };
  }
</script>

<button on:click={showMessage}>Show flash message</button>

Client-side fetching and redirecting

In most cases the flash message will update automatically on redirect or navigation, with one exception: When using fetch, you must call updateFlash afterwards:

<script lang="ts">
  import { updateFlash } from 'sveltekit-flash-message';
  import { page } from '$app/stores';

  async function submitForm(e: Event) {
    const form = e.target as HTMLFormElement;
    const body = new FormData(e.target as HTMLFormElement);

    await fetch(form.action, { method: 'POST', body });
    await updateFlash(page);
  }
</script>

<form method="POST" action="/test" on:submit|preventDefault={submitForm}>
  <input type="text" name="test" value="TEST" />
  <button>Submit with fetch</button>
</form>

updateFlash can take a second parameter, which is used to run a function before updating, so navigation events will pass through before showing the flash message. This is useful when you want to redirect based on the fetch response:

async function submitForm(e: Event) {
  const response = await fetch(new URL('/logout', $page.url), { method: 'POST' });
  if (response.redirected) {
    await updateFlash(page, () => goto(response.url, { invalidateAll: true }));
  }
}

Toast messages, event-style

A common use case for flash messages is to show a toast notification, but a toast is more of an event than data that should be displayed on the page, as we've done previously. But you can use the flash store as an event handler by subscribing to it:

src/routes/+layout.svelte

import { getFlash } from 'sveltekit-flash-message';
import { page } from '$app/stores';
import toast, { Toaster } from 'svelte-french-toast';

const flash = getFlash(page);

flash.subscribe(($flash) => {
  if (!$flash) return;

  toast($flash.message, {
    icon: $flash.type == 'success' ? 'โœ…' : 'โŒ'
  });

  // Clearing the flash message could sometimes
  // be required here to avoid double-toasting.
  flash.set(undefined);
});

Flash message options

In a top-level component, most likely a +layout.svelte file, you can specify options for getFlash. Note that options can only be set the first time you call getFlash for a certain page/layout, usually in the top-level component. Subsequent calls to getFlash in components below cannot have any options. (See the first call to it as a kind of constructor.)

const flash = getFlash(page, {
  clearOnNavigate: true,
  clearAfterMs: undefined,
  clearArray: false,
  flashCookieOptions: CookieSerializeOptions
});

clearOnNavigate

If true (the default), the flash message will be removed when navigating to a different url.

clearAfterMs

Can be set to a number of milliseconds before the flash message is automatically set to undefined.

clearArray

If you specify App.PageData['flash'] as an array, the library will accomodate for that and will concatenate messages into the array instead of replacing them. But if you want to always clear the previous messages, set the clearArray option to true.

flashCookieOptions

You can change the options for the cookie being sent, like this on the server:

import { loadFlash, flashCookieOptions } from 'sveltekit-flash-message/server';

flashCookieOptions.sameSite = 'lax';

export const load = loadFlash(async (event) => {
  // ...load function...
});

And correspondingly, on the client:

const flash = getFlash(page, {
  flashCookieOptions: { sameSite: 'lax' }
});

All options can be found in the cookie npm package. Default options for the flash cookie are:

{
  path: '/',
  maxAge: 120,
  sameSite: 'strict',
  httpOnly: false // Setting this to true will most likely break things client-side.
}

The name of the cookie, flash, cannot be changed currently, let me know if that's inconvenient. โšก

Securing the flash message

Since the flash message is transferred in a cookie, it can be easily tampered with, so don't trust its content. Treat it like you do with any user data - hanging from a ten-foot pole over a fiery pit. ๐Ÿ”ฅ So never use {@html} to display it, and if you need to persist it for some reason, make sure you validate it.

Together with Superforms

The sister library to sveltekit-flash-message is Superforms, the all-in-one solution for forms in SvelteKit. You can use them together without any extra work, but there are options for closer integration, found here on the Superforms website.

Notes

When setting cookies in a response

If you're using +hooks.server.ts/js, or anywhere you have access to response, calling response.headers.set('set-cookie', ...) will discard the flash message cookie. You must use response.headers.append instead.

Redirecting in the load function

In SvelteKit, links are preloaded on hover for increased responsiveness of the app. This can have the side-effect of accidentally setting a flash cookie, if a flash message redirect is made in a load function, and the user hovers over a link leading to it, so it is preloaded. To prevent this, set the data-sveltekit-preload-data="tap" attribute on links where a redirect could happen in the load function.

Migration guides

From 0.x to 1.x

The only thing you need to do when upgrading to 1.x is to remove all calls to updateFlash in use:enhance.

 <form
    method="POST"
-   use:enhance={() =>
-     ({ update }) =>
-       updateFlash(page, update)}
+   use:enhance
 >

From 1.x to 2.x

  1. Rename functions:
  • initFlash is deprecated, getFlash can now be used directly instead.
  • loadFlashMessage is deprecated and renamed to loadFlash.
  1. If you've added the beforeNavigate snippet that clears the flash message after navigation - it can now be removed since it's automatic (though it can be prevented by setting the clearOnNavigate option to false).

  2. If you're using the snippet for clearing the message after a certain amount of time, you can remove it and use the clearAfterMs option instead.

Feedback and issues

Please open a github issue for suggestions, if you find a bug or have feedback in general!

More Repositories

1

sveltekit-superforms

Making SvelteKit forms a pleasure to use!
TypeScript
2,116
star
2

sveltekit-rate-limiter

A modular rate limiter for SvelteKit. Use in password resets, account registration, etc.
TypeScript
195
star
3

mithril-hx

Haxe externs for Mithril (JS MVC framework)
Haxe
181
star
4

buddy

Your friendly BDD testing library for Haxe!
Haxe
96
star
5

dataclass

Give your Data some class!
Haxe
47
star
6

HaxeContracts

A Design by contract library for Haxe.
Haxe
44
star
7

slambda

Short Lambda expressions in a tiny Haxe library
Haxe
40
star
8

haxedci

DCI for Haxe!
Haxe
40
star
9

haxedci-example

Example code for haxedci (DCI library for Haxe)
Haxe
36
star
10

haxelow

A small, flat JSON database library for Haxe.
Haxe
35
star
11

superforms-web

Website for the SvelteKit library Superforms
Svelte
33
star
12

deepstate

An immutable state container for Haxe 4, similar to Redux.
Haxe
30
star
13

immutable-hx

Makes even local vars immutable in Haxe 4.
Haxe
29
star
14

erazor

A Haxe implementation of the Razor view engine
Haxe
19
star
15

sveltekit-spa

[DEPRECATED] How to configure SvelteKit to become a SPA with client-side routing.
Svelte
18
star
16

unject

A dependency injection library for haXe, inspired by Ninject.
Haxe
16
star
17

umock

A mocking framework for Haxe, inspired by Moq.
Haxe
13
star
18

uniontypes

Union types in Haxe, similar to Typescript
Haxe
12
star
19

ivento-dci

A DCI library for C#, using extension methods
C#
9
star
20

htemplate

A cross-platform template engine for haXe
Haxe
7
star
21

SnakeDCI

A demonstration of DCI in game programming, creating the classic Snake game in Haxe and the Phaser game framework.
Haxe
7
star
22

prisma-to-zod

Generate Zod validation schemas from a Prisma schema.
TypeScript
6
star
23

typesafe-i18n-with-sveltekit

SvelteKit and typesafe-i18n for modern multi-language sites.
TypeScript
5
star
24

vite-plugin-haxe

Run Haxe code on Vite.
TypeScript
5
star
25

simplest-sitegen

The simplest static sitegen there is. Build a modern, fully working website with only HTML.
HTML
5
star
26

superforms-examples

Examples for Superforms.
Svelte
5
star
27

nodehost

Quick Node.js hosting on ubuntu/debian with nginx
Haxe
3
star
28

NosceIpsum

A gentle reminder to keep focus on the Now
C#
2
star
29

MakeItPortable

An autohotkey library for creation of Portable Applications
2
star
30

viagrant

Quick 'n dirty node script for building Vagrant files.
Shell
2
star
31

dcisniffer

A DCI Standard for PHP, to be used with PHP_CodeSniffer.
PHP
2
star
32

odm-web

Website created for the ODM Haxe meetup.
Haxe
2
star
33

prismic-hx

Haxe externs for prismic.io
Haxe
1
star
34

dilemma

Prisoner's dilemma in Svelte
Svelte
1
star
35

asynctools

Haxe implementation of the npm async package
Haxe
1
star
36

eslint-plugin-dci-lint

DCI linting for Typescript and ESLint
TypeScript
1
star
37

vite-plugin-svelte-globalcss

Use global css/sass in a sveltekit app.
TypeScript
1
star
38

empty-haxe-project

Empty Haxe project starting point. Node/Neko/Js ready.
Haxe
1
star