Actions de formulaire
Un fichier +page.server.js
peut exporter des actions, ce qui vous permet d’envoyer des données
avec POST
vers le serveur en utilisant un élément de formulaire <form>
.
Lorsque vous utilisez un élément <form>
, la présence de JavaScript côté client est optionnelle,
mais vous pouvez facilement améliorer progressivement vos interactions de formulaire avec
JavaScript pour fournir la meilleure expérience utilisateur.
Actions par défaut
Dans le cas le plus simple, une page déclare une action par défaut appelée default
:
/** @satisfies {import('./$types').Actions} */
export const const actions: {
default: (event: any) => Promise<void>;
}
actions = {
default: (event: any) => Promise<void>
default: async (event: any
event) => {
// TODO identifier l'utilisateur
}
};
import type { type Actions = {
[x: string]: Kit.Action<Record<string, any>, void | Record<string, any>, string | null>;
}
type Actions = {
[x: string]: Kit.Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions } from './$types';
export const const actions: {
default: (event: Kit.RequestEvent<Record<string, any>, string | null>) => Promise<void>;
}
actions = {
default: (event: Kit.RequestEvent<Record<string, any>, string | null>) => Promise<void>
default: async (event: Kit.RequestEvent<Record<string, any>, string | null>
event) => {
// TODO identifier l'utilisateur
}
} satisfies type Actions = {
[x: string]: Kit.Action<Record<string, any>, void | Record<string, any>, string | null>;
}
type Actions = {
[x: string]: Kit.Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions;
Pour invoquer cette action depuis la page /login
, ajouter simplement un élément <form>
— aucun
JavaScript n’est nécessaire :
<form method="POST">
<label>
Email
<input name="email" type="email">
</label>
<label>
Mot de passe
<input name="password" type="password">
</label>
<button>Se connecter</button>
</form>
Lorsque le bouton est cliqué, le navigateur va envoyer au serveur les données du formulaire via une
requête POST
, en exécutant l’action par défaut.
Les actions utilisent toujours des requêtes
POST
, puisque les requêtesGET
ne sont pas censées avoir d’effets de bord.
Nous pouvons aussi invoquer l’action depuis d’autres pages (par exemple, s’il y a un widget de
connexion dans la barre de navigation du layout racine) en ajoutant l’attribut action
pointant
vers la page :
<form method="POST" action="/login">
<!-- contenu -->
</form>
Actions nommées
Plutôt qu’une seule action default
par défaut, une page peut avoir autant d’actions nommées que
nécessaire :
/** @satisfies {import('./$types').Actions} */
export const const actions: {
login: (event: any) => Promise<void>;
register: (event: any) => Promise<void>;
}
actions = {
default: async (event) => {
login: (event: any) => Promise<void>
login: async (event: any
event) => {
// TODO connecter l'utilisateur
},
register: (event: any) => Promise<void>
register: async (event: any
event) => {
// TODO inscrire l'utilisateur
}
};
import type { type Actions = {
[x: string]: Kit.Action<Record<string, any>, void | Record<string, any>, string | null>;
}
type Actions = {
[x: string]: Kit.Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions } from './$types';
export const const actions: {
login: (event: Kit.RequestEvent<Record<string, any>, string | null>) => Promise<void>;
register: (event: Kit.RequestEvent<Record<string, any>, string | null>) => Promise<...>;
}
actions = {
default: async (event) => {
login: (event: Kit.RequestEvent<Record<string, any>, string | null>) => Promise<void>
login: async (event: Kit.RequestEvent<Record<string, any>, string | null>
event) => {
// TODO connecter l'utilisateur
},
register: (event: Kit.RequestEvent<Record<string, any>, string | null>) => Promise<void>
register: async (event: Kit.RequestEvent<Record<string, any>, string | null>
event) => {
// TODO inscrire l'utilisateur
}
} satisfies type Actions = {
[x: string]: Kit.Action<Record<string, any>, void | Record<string, any>, string | null>;
}
type Actions = {
[x: string]: Kit.Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions;
Pour invoquer une action nommée, ajoutez un paramètre de requête comportant le nom de l’action
préfixé par un caractère /
:
<form method="POST" action="?/register">
<form method="POST" action="/login?/register">
Similaire à l’attribut action
, nous pouvons utiliser l’attribut formaction
sur un bouton pour
envoyer avec POST
les mêmes données de formulaire à une action différente de celle de l’élément
<form>
parent :
<form method="POST" action="?/login">
<label>
Email
<input name="email" type="email">
</label>
<label>
Mot de passe
<input name="password" type="password">
</label>
<button>Se connecter</button>
<button formaction="?/register">S'inscrire</button>
</form>
Il n’est pas possible d’avoir des actions par défaut dans le même fichier que des actions nommées, car si vous ciblez une action nommée avec POST sans redirection, le paramètre de requête est persisté dans l’URL, ce qui signifie que la prochaine requête POST par défaut va cibler l’action nommée précédente.
Anatomie d’une action
Chaque action reçoit un objet RequestEvent
, vous permettant de lire les données avec
request.formData()
. Après le traitement de la requête (par exemple, pour connecter l’utilisateur
ou l’utilisatrice en définissant un cookie), l’action peut répondre avec des données qui seront
disponibles via la propriété form
sur la page correspondante, et via page.form
dans toute
l’application, jusqu’à sa prochaine mise à jour.
import * as module "$lib/server/db"
db from '$lib/server/db';
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ cookies: Cookies
Get or set cookies related to the current request
cookies }) {
const const user: any
user = await module "$lib/server/db"
db.getUserFromSession(cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefined
Gets a cookie that was previously set with cookies.set
, or from the request headers.
get('sessionid'));
return { user: any
user };
}
/** @satisfies {import('./$types').Actions} */
export const const actions: {
login: ({ cookies, request }: RequestEvent<Record<string, any>, string | null>) => Promise<{
success: boolean;
}>;
register: (event: RequestEvent<Record<string, any>, string | null>) => Promise<...>;
}
actions = {
login: ({ cookies, request }: RequestEvent<Record<string, any>, string | null>) => Promise<{
success: boolean;
}>
login: async ({ cookies: Cookies
Get or set cookies related to the current request
cookies, request: Request
The original request object.
request }) => {
const const data: FormData
data = await request: Request
The original request object.
request.Body.formData(): Promise<FormData>
formData();
const const email: FormDataEntryValue | null
email = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('email');
const const password: FormDataEntryValue | null
password = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('password');
const const user: any
user = await module "$lib/server/db"
db.getUser(const email: FormDataEntryValue | null
email);
cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.set: (name: string, value: string, opts: CookieSerializeOptions & {
path: string;
}) => void
Sets a cookie. This will add a set-cookie
header to the response, but also make the cookie available via cookies.get
or cookies.getAll
during the current request.
The httpOnly
and secure
options are true
by default (except on http://localhost, where secure
is false
), and must be explicitly disabled if you want cookies to be readable by client-side JavaScript and/or transmitted over HTTP. The sameSite
option defaults to lax
.
You must specify a path
for the cookie. In most cases you should explicitly set path: '/'
to make the cookie available throughout your app. You can use relative paths, or set path: ''
to make the cookie only available on the current path and its children
set('sessionid', await module "$lib/server/db"
db.createSession(const user: any
user), { path: string
Specifies the value for the
{@link
https://tools.ietf.org/html/rfc6265#section-5.2.4 Path
Set-Cookie
attribute
}
.
By default, the path is considered the “default path”.
path: '/' });
return { success: boolean
success: true };
},
register: (event: RequestEvent<Record<string, any>, string | null>) => Promise<void>
register: async (event: RequestEvent<Record<string, any>, string | null>
event) => {
// TODO inscrire l'utilisateur
}
};
import * as module "$lib/server/db"
db from '$lib/server/db';
import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad, type Actions = {
[x: string]: Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = async ({ cookies: Cookies
Get or set cookies related to the current request
cookies }) => {
const const user: any
user = await module "$lib/server/db"
db.getUserFromSession(cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefined
Gets a cookie that was previously set with cookies.set
, or from the request headers.
get('sessionid'));
return { user: any
user };
};
export const const actions: {
login: ({ cookies, request }: RequestEvent<Record<string, any>, string | null>) => Promise<{
success: boolean;
}>;
register: (event: RequestEvent<Record<string, any>, string | null>) => Promise<...>;
}
actions = {
login: ({ cookies, request }: RequestEvent<Record<string, any>, string | null>) => Promise<{
success: boolean;
}>
login: async ({ cookies: Cookies
Get or set cookies related to the current request
cookies, request: Request
The original request object.
request }) => {
const const data: FormData
data = await request: Request
The original request object.
request.Body.formData(): Promise<FormData>
formData();
const const email: FormDataEntryValue | null
email = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('email');
const const password: FormDataEntryValue | null
password = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('password');
const const user: any
user = await module "$lib/server/db"
db.getUser(const email: FormDataEntryValue | null
email);
cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.set: (name: string, value: string, opts: CookieSerializeOptions & {
path: string;
}) => void
Sets a cookie. This will add a set-cookie
header to the response, but also make the cookie available via cookies.get
or cookies.getAll
during the current request.
The httpOnly
and secure
options are true
by default (except on http://localhost, where secure
is false
), and must be explicitly disabled if you want cookies to be readable by client-side JavaScript and/or transmitted over HTTP. The sameSite
option defaults to lax
.
You must specify a path
for the cookie. In most cases you should explicitly set path: '/'
to make the cookie available throughout your app. You can use relative paths, or set path: ''
to make the cookie only available on the current path and its children
set('sessionid', await module "$lib/server/db"
db.createSession(const user: any
user), { path: string
Specifies the value for the
{@link
https://tools.ietf.org/html/rfc6265#section-5.2.4 Path
Set-Cookie
attribute
}
.
By default, the path is considered the “default path”.
path: '/' });
return { success: boolean
success: true };
},
register: (event: RequestEvent<Record<string, any>, string | null>) => Promise<void>
register: async (event: RequestEvent<Record<string, any>, string | null>
event) => {
// TODO inscrire l'utilisateur
}
} satisfies type Actions = {
[x: string]: Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions;
<script>
/** @type {import('./$types').PageProps} */
let { data, form } = $props();
</script>
{#if form?.success}
<!-- ce message est éphémère ; il existe car la page a été rendu en réponse à une soumission
de formulaire. il disparaîtra si l'utilisateur recharge la page -->
<p>Connexion réussie ! Content de vous revoir, {data.user.name}</p>
{/if}
<script lang="ts">
import type { PageProps } from './$types';
let { data, form }: PageProps = $props();
</script>
{#if form?.success}
<!-- ce message est éphémère ; il existe car la page a été rendu en réponse à une soumission
de formulaire. il disparaîtra si l'utilisateur recharge la page -->
<p>Connexion réussie ! Content de vous revoir, {data.user.name}</p>
{/if}
Legacy mode
PageProps
a été ajouté dans la version 2.16.0 de SvelteKit. Dans les versions antérieures, vous deviez typer les propriétésdata
etform
individuellement :+page/** @type {{ data: import('./$types').PageData, form: import('./$types').ActionData }} */ let {
let data: any
data,let form: any
form } =
function $props(): any namespace $props
$props();Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
import type {
import PageData
PageData,import ActionData
ActionData } from './$types'; let {let data: PageData
data,let form: ActionData
form }: {data: PageData
data:import PageData
PageData,form: ActionData
form:import ActionData
ActionData } =
function $props(): any namespace $props
$props();Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
Avec Svelte 4, vous utiliseriez plutôt
export let data
etexport let form
pour déclarer les propriétés.
Erreurs de validation
Si la requête n’a pas pu être traitée à cause de données non valides, vous pouvez renvoyer des
erreurs de validation — en plus des valeurs précédemment soumises par le formulaire — à
l’utilisateur ou l’utilisatrice afin qu’il ou elle ré-essaye. La fonction fail
vous permet de
renvoyer un statut HTTP (généralement 400 ou 422, dans le cas d’erreurs de validation) avec les
données. Le statut est rendu disponible via page.status
et les données via form
:
import { function fail(status: number): ActionFailure<undefined> (+1 overload)
Create an ActionFailure
object.
fail } from '@sveltejs/kit';
import * as module "$lib/server/db"
db from '$lib/server/db';
/** @satisfies {import('./$types').Actions} */
export const const actions: {
login: ({ cookies, request }: RequestEvent<Record<string, any>, string | null>) => Promise<ActionFailure<{
email: string | null;
missing: boolean;
}> | ActionFailure<{
...;
}> | {
...;
}>;
register: (event: RequestEvent<...>) => Promise<...>;
}
actions = {
login: ({ cookies, request }: RequestEvent<Record<string, any>, string | null>) => Promise<ActionFailure<{
email: string | null;
missing: boolean;
}> | ActionFailure<{
email: FormDataEntryValue;
incorrect: boolean;
}> | {
...;
}>
login: async ({ cookies: Cookies
Get or set cookies related to the current request
cookies, request: Request
The original request object.
request }) => {
const const data: FormData
data = await request: Request
The original request object.
request.Body.formData(): Promise<FormData>
formData();
const const email: FormDataEntryValue | null
email = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('email');
const const password: FormDataEntryValue | null
password = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('password');
if (!const email: FormDataEntryValue | null
email) {
return fail<{
email: string | null;
missing: boolean;
}>(status: number, data: {
email: string | null;
missing: boolean;
}): ActionFailure<{
email: string | null;
missing: boolean;
}> (+1 overload)
Create an ActionFailure
object.
email: string | null
email, missing: boolean
missing: true });
}
const const user: any
user = await module "$lib/server/db"
db.getUser(const email: FormDataEntryValue
email);
if (!const user: any
user || const user: any
user.password !== module "$lib/server/db"
db.hash(const password: FormDataEntryValue | null
password)) {
return fail<{
email: FormDataEntryValue;
incorrect: boolean;
}>(status: number, data: {
email: FormDataEntryValue;
incorrect: boolean;
}): ActionFailure<{
email: FormDataEntryValue;
incorrect: boolean;
}> (+1 overload)Create an ActionFailure
object.
email: FormDataEntryValue
email, incorrect: boolean
incorrect: true });
}
cookies: Cookies
Get or set cookies related to the current request
Cookies.set: (name: string, value: string, opts: CookieSerializeOptions & {
path: string;
}) => void
Sets a cookie. This will add a set-cookie
header to the response, but also make the cookie available via cookies.get
or cookies.getAll
during the current request.
The httpOnly
and secure
options are true
by default (except on http://localhost, where secure
is false
), and must be explicitly disabled if you want cookies to be readable by client-side JavaScript and/or transmitted over HTTP. The sameSite
option defaults to lax
.
You must specify a path
for the cookie. In most cases you should explicitly set path: '/'
to make the cookie available throughout your app. You can use relative paths, or set path: ''
to make the cookie only available on the current path and its children
module "$lib/server/db"
db.createSession(const user: any
user), { path: string
Specifies the value for the
{@link
https://tools.ietf.org/html/rfc6265#section-5.2.4 Path
Set-Cookie
attribute
}
.
By default, the path is considered the “default path”.
success: boolean
success: true };
},
register: (event: RequestEvent<Record<string, any>, string | null>) => Promise<void>
register: async (event: RequestEvent<Record<string, any>, string | null>
event) => {
// TODO inscrire l'utilisateur
}
};import { function fail(status: number): ActionFailure<undefined> (+1 overload)
Create an ActionFailure
object.
fail } from '@sveltejs/kit';
import * as module "$lib/server/db"
db from '$lib/server/db';
import type { type Actions = {
[x: string]: Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions } from './$types';
export const const actions: {
login: ({ cookies, request }: RequestEvent<Record<string, any>, string | null>) => Promise<ActionFailure<{
email: string | null;
missing: boolean;
}> | ActionFailure<{
...;
}> | {
...;
}>;
register: (event: RequestEvent<...>) => Promise<...>;
}
actions = {
login: ({ cookies, request }: RequestEvent<Record<string, any>, string | null>) => Promise<ActionFailure<{
email: string | null;
missing: boolean;
}> | ActionFailure<{
email: FormDataEntryValue;
incorrect: boolean;
}> | {
...;
}>
login: async ({ cookies: Cookies
Get or set cookies related to the current request
cookies, request: Request
The original request object.
request }) => {
const const data: FormData
data = await request: Request
The original request object.
request.Body.formData(): Promise<FormData>
formData();
const const email: FormDataEntryValue | null
email = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('email');
const const password: FormDataEntryValue | null
password = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('password');
if (!const email: FormDataEntryValue | null
email) {
return fail<{
email: string | null;
missing: boolean;
}>(status: number, data: {
email: string | null;
missing: boolean;
}): ActionFailure<{
email: string | null;
missing: boolean;
}> (+1 overload)
Create an ActionFailure
object.
email: string | null
email, missing: boolean
missing: true });
}
const const user: any
user = await module "$lib/server/db"
db.getUser(const email: FormDataEntryValue
email);
if (!const user: any
user || const user: any
user.password !== module "$lib/server/db"
db.hash(const password: FormDataEntryValue | null
password)) {
return fail<{
email: FormDataEntryValue;
incorrect: boolean;
}>(status: number, data: {
email: FormDataEntryValue;
incorrect: boolean;
}): ActionFailure<{
email: FormDataEntryValue;
incorrect: boolean;
}> (+1 overload)Create an ActionFailure
object.
email: FormDataEntryValue
email, incorrect: boolean
incorrect: true });
}
cookies: Cookies
Get or set cookies related to the current request
Cookies.set: (name: string, value: string, opts: CookieSerializeOptions & {
path: string;
}) => void
Sets a cookie. This will add a set-cookie
header to the response, but also make the cookie available via cookies.get
or cookies.getAll
during the current request.
The httpOnly
and secure
options are true
by default (except on http://localhost, where secure
is false
), and must be explicitly disabled if you want cookies to be readable by client-side JavaScript and/or transmitted over HTTP. The sameSite
option defaults to lax
.
You must specify a path
for the cookie. In most cases you should explicitly set path: '/'
to make the cookie available throughout your app. You can use relative paths, or set path: ''
to make the cookie only available on the current path and its children
module "$lib/server/db"
db.createSession(const user: any
user), { path: string
Specifies the value for the
{@link
https://tools.ietf.org/html/rfc6265#section-5.2.4 Path
Set-Cookie
attribute
}
.
By default, the path is considered the “default path”.
success: boolean
success: true };
},
register: (event: RequestEvent<Record<string, any>, string | null>) => Promise<void>
register: async (event: RequestEvent<Record<string, any>, string | null>
event) => {
// TODO inscrire l'utilisateur
}
} satisfies type Actions = {
[x: string]: Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions;Notez que par précaution, nous renvoyons uniquement l’email à la page — pas le mot de passe.
<form method="POST" action="?/login">
{#if form?.missing}<p class="error">Le champ email est requis</p>{/if}
{#if form?.incorrect}<p class="error">Identifiants invalides !</p>{/if}
<label>
Email
<input name="email" type="email" value={form?.email ?? ''}>
</label>
<label>
Mot de passe
<input name="password" type="password">
</label>
<button>Se connecter</button>
<button formaction="?/register">S'inscrire</button>
</form>
Les données renvoyées doivent être sérialisables en JSON. À part ça, la structure est complètement
libre. Par exemple, si vous avez plusieurs formulaires sur la même page, vous pourriez différencier
à quel élément <form>
les données form
font référence avec une propriété id
ou similaire.
Redirections
Les redirections (et les erreurs) fonctionnent exactement de la même façon que dans
load
:
import { function fail(status: number): ActionFailure<undefined> (+1 overload)
Create an ActionFailure
object.
fail, function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other
: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect
: redirect will keep the request method
308 Permanent Redirect
: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
import * as module "$lib/server/db"
db from '$lib/server/db';
/** @satisfies {import('./$types').Actions} */
export const const actions: {
login: ({ cookies, request, url }: RequestEvent<Record<string, any>, string | null>) => Promise<ActionFailure<{
email: FormDataEntryValue | null;
missing: boolean;
}> | ActionFailure<...> | {
...;
}>;
register: (event: RequestEvent<...>) => Promise<...>;
}
actions = {
login: ({ cookies, request, url }: RequestEvent<Record<string, any>, string | null>) => Promise<ActionFailure<{
email: FormDataEntryValue | null;
missing: boolean;
}> | ActionFailure<...> | {
...;
}>
login: async ({ cookies: Cookies
Get or set cookies related to the current request
cookies, request: Request
The original request object.
request, url: URL
The requested URL.
url }) => {
const const data: FormData
data = await request: Request
The original request object.
request.Body.formData(): Promise<FormData>
formData();
const const email: FormDataEntryValue | null
email = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('email');
const const password: FormDataEntryValue | null
password = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('password');
const const user: any
user = await module "$lib/server/db"
db.getUser(const email: FormDataEntryValue | null
email);
if (!const user: any
user) {
return fail<{
email: FormDataEntryValue | null;
missing: boolean;
}>(status: number, data: {
email: FormDataEntryValue | null;
missing: boolean;
}): ActionFailure<...> (+1 overload)
Create an ActionFailure
object.
fail(400, { email: FormDataEntryValue | null
email, missing: boolean
missing: true });
}
if (const user: any
user.password !== module "$lib/server/db"
db.hash(const password: FormDataEntryValue | null
password)) {
return fail<{
email: FormDataEntryValue | null;
incorrect: boolean;
}>(status: number, data: {
email: FormDataEntryValue | null;
incorrect: boolean;
}): ActionFailure<...> (+1 overload)
Create an ActionFailure
object.
fail(400, { email: FormDataEntryValue | null
email, incorrect: boolean
incorrect: true });
}
cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.set: (name: string, value: string, opts: CookieSerializeOptions & {
path: string;
}) => void
Sets a cookie. This will add a set-cookie
header to the response, but also make the cookie available via cookies.get
or cookies.getAll
during the current request.
The httpOnly
and secure
options are true
by default (except on http://localhost, where secure
is false
), and must be explicitly disabled if you want cookies to be readable by client-side JavaScript and/or transmitted over HTTP. The sameSite
option defaults to lax
.
You must specify a path
for the cookie. In most cases you should explicitly set path: '/'
to make the cookie available throughout your app. You can use relative paths, or set path: ''
to make the cookie only available on the current path and its children
set('sessionid', await module "$lib/server/db"
db.createSession(const user: any
user), { path: string
Specifies the value for the
{@link
https://tools.ietf.org/html/rfc6265#section-5.2.4 Path
Set-Cookie
attribute
}
.
By default, the path is considered the “default path”.
path: '/' });
if (url: URL
The requested URL.
url.URL.searchParams: URLSearchParams
searchParams.URLSearchParams.has(name: string, value?: string): boolean
Returns a Boolean indicating if such a search parameter exists.
has('redirectTo')) {
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other
: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect
: redirect will keep the request method
308 Permanent Redirect
: redirect will keep the request method, SEO will be transferred to the new page
redirect(303, url.searchParams.get('redirectTo'));
}
return { success: boolean
success: true };
},
register: (event: RequestEvent<Record<string, any>, string | null>) => Promise<void>
register: async (event: RequestEvent<Record<string, any>, string | null>
event) => {
// TODO inscrire l'utilisateur
}
};
import { function fail(status: number): ActionFailure<undefined> (+1 overload)
Create an ActionFailure
object.
fail, function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other
: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect
: redirect will keep the request method
308 Permanent Redirect
: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
import * as module "$lib/server/db"
db from '$lib/server/db';
import type { type Actions = {
[x: string]: Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions } from './$types';
export const const actions: {
login: ({ cookies, request, url }: RequestEvent<Record<string, any>, string | null>) => Promise<ActionFailure<{
email: FormDataEntryValue | null;
missing: boolean;
}> | ActionFailure<...> | {
...;
}>;
register: (event: RequestEvent<...>) => Promise<...>;
}
actions = {
login: ({ cookies, request, url }: RequestEvent<Record<string, any>, string | null>) => Promise<ActionFailure<{
email: FormDataEntryValue | null;
missing: boolean;
}> | ActionFailure<...> | {
...;
}>
login: async ({ cookies: Cookies
Get or set cookies related to the current request
cookies, request: Request
The original request object.
request, url: URL
The requested URL.
url }) => {
const const data: FormData
data = await request: Request
The original request object.
request.Body.formData(): Promise<FormData>
formData();
const const email: FormDataEntryValue | null
email = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('email');
const const password: FormDataEntryValue | null
password = const data: FormData
data.FormData.get(name: string): FormDataEntryValue | null
get('password');
const const user: any
user = await module "$lib/server/db"
db.getUser(const email: FormDataEntryValue | null
email);
if (!const user: any
user) {
return fail<{
email: FormDataEntryValue | null;
missing: boolean;
}>(status: number, data: {
email: FormDataEntryValue | null;
missing: boolean;
}): ActionFailure<...> (+1 overload)
Create an ActionFailure
object.
fail(400, { email: FormDataEntryValue | null
email, missing: boolean
missing: true });
}
if (const user: any
user.password !== module "$lib/server/db"
db.hash(const password: FormDataEntryValue | null
password)) {
return fail<{
email: FormDataEntryValue | null;
incorrect: boolean;
}>(status: number, data: {
email: FormDataEntryValue | null;
incorrect: boolean;
}): ActionFailure<...> (+1 overload)
Create an ActionFailure
object.
fail(400, { email: FormDataEntryValue | null
email, incorrect: boolean
incorrect: true });
}
cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.set: (name: string, value: string, opts: CookieSerializeOptions & {
path: string;
}) => void
Sets a cookie. This will add a set-cookie
header to the response, but also make the cookie available via cookies.get
or cookies.getAll
during the current request.
The httpOnly
and secure
options are true
by default (except on http://localhost, where secure
is false
), and must be explicitly disabled if you want cookies to be readable by client-side JavaScript and/or transmitted over HTTP. The sameSite
option defaults to lax
.
You must specify a path
for the cookie. In most cases you should explicitly set path: '/'
to make the cookie available throughout your app. You can use relative paths, or set path: ''
to make the cookie only available on the current path and its children
set('sessionid', await module "$lib/server/db"
db.createSession(const user: any
user), { path: string
Specifies the value for the
{@link
https://tools.ietf.org/html/rfc6265#section-5.2.4 Path
Set-Cookie
attribute
}
.
By default, the path is considered the “default path”.
path: '/' });
if (url: URL
The requested URL.
url.URL.searchParams: URLSearchParams
searchParams.URLSearchParams.has(name: string, value?: string): boolean
Returns a Boolean indicating if such a search parameter exists.
has('redirectTo')) {
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other
: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect
: redirect will keep the request method
308 Permanent Redirect
: redirect will keep the request method, SEO will be transferred to the new page
redirect(303, url.searchParams.get('redirectTo'));
}
return { success: boolean
success: true };
},
register: (event: RequestEvent<Record<string, any>, string | null>) => Promise<void>
register: async (event: RequestEvent<Record<string, any>, string | null>
event) => {
// TODO inscrire l'utilisateur
}
} satisfies type Actions = {
[x: string]: Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions;
Chargement de données
Après l’exécution d’une action, la page sera re-rendue (à moins qu’une redirection ou une erreur
inattendue se produise), avec la valeur de retour de l’action rendue disponible dans la page en tant
que propriété form
. Ceci signifie que les fonctions load
de la page vont être exécutées après
la fin de l’exécution d’une action.
Notez que handle
est exécuté avant l’invocation de l’action, et n’est pas ré-exécutée avant les
fonctions load
. Ceci signifie que si, par exemple, vous utiliser handle
pour remplir
event.locals
en fonction d’un cookie, vous devez mettre à jour event.locals
lorsque vous
définissez ou supprimez le cookie lors d’une action :
/** @type {import('@sveltejs/kit').Handle} */
export async function function handle(input: {
event: RequestEvent;
resolve: (event: RequestEvent, opts?: ResolveOptions) => MaybePromise<Response>;
}): MaybePromise<...>
handle({ event: RequestEvent<Partial<Record<string, string>>, string | null>
event, resolve: (event: RequestEvent, opts?: ResolveOptions) => MaybePromise<Response>
resolve }) {
event: RequestEvent<Partial<Record<string, string>>, string | null>
event.RequestEvent<Partial<Record<string, string>>, string | null>.locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user: {
name: string;
} | null
user = await function getUser(sessionid: string | undefined): {
name: string;
}
getUser(event: RequestEvent<Partial<Record<string, string>>, string | null>
event.RequestEvent<Partial<Record<string, string>>, string | null>.cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefined
Gets a cookie that was previously set with cookies.set
, or from the request headers.
get('sessionid'));
return resolve: (event: RequestEvent, opts?: ResolveOptions) => MaybePromise<Response>
resolve(event: RequestEvent<Partial<Record<string, string>>, string | null>
event);
}
import type { type Handle = (input: {
event: RequestEvent;
resolve: (event: RequestEvent, opts?: ResolveOptions) => MaybePromise<Response>;
}) => MaybePromise<...>
The handle
hook runs every time the SvelteKit server receives a request and
determines the response.
It receives an event
object representing the request and a function called resolve
, which renders the route and generates a Response
.
This allows you to modify response headers or bodies, or bypass SvelteKit entirely (for implementing routes programmatically, for example).
Handle } from '@sveltejs/kit';
export const const handle: Handle
handle: type Handle = (input: {
event: RequestEvent;
resolve: (event: RequestEvent, opts?: ResolveOptions) => MaybePromise<Response>;
}) => MaybePromise<...>
The handle
hook runs every time the SvelteKit server receives a request and
determines the response.
It receives an event
object representing the request and a function called resolve
, which renders the route and generates a Response
.
This allows you to modify response headers or bodies, or bypass SvelteKit entirely (for implementing routes programmatically, for example).
Handle = async ({ event: RequestEvent<Partial<Record<string, string>>, string | null>
event, resolve: (event: RequestEvent, opts?: ResolveOptions) => MaybePromise<Response>
resolve }) => {
event: RequestEvent<Partial<Record<string, string>>, string | null>
event.RequestEvent<Partial<Record<string, string>>, string | null>.locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user: {
name: string;
} | null
user = await function getUser(sessionid: string | undefined): {
name: string;
}
getUser(event: RequestEvent<Partial<Record<string, string>>, string | null>
event.RequestEvent<Partial<Record<string, string>>, string | null>.cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefined
Gets a cookie that was previously set with cookies.set
, or from the request headers.
get('sessionid'));
return resolve: (event: RequestEvent, opts?: ResolveOptions) => MaybePromise<Response>
resolve(event: RequestEvent<Partial<Record<string, string>>, string | null>
event);
};
/** @type {import('./$types').PageServerLoad} */
export function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>
event) {
return {
user: {
name: string;
} | null
user: event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>
event.RequestEvent<Record<string, any>, string | null>.locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user: {
name: string;
} | null
user
};
}
/** @satisfies {import('./$types').Actions} */
export const const actions: {
logout: (event: RequestEvent<Record<string, any>, string | null>) => Promise<void>;
}
actions = {
logout: (event: RequestEvent<Record<string, any>, string | null>) => Promise<void>
logout: async (event: RequestEvent<Record<string, any>, string | null>
event) => {
event: RequestEvent<Record<string, any>, string | null>
event.RequestEvent<Record<string, any>, string | null>.cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.delete: (name: string, opts: CookieSerializeOptions & {
path: string;
}) => void
Deletes a cookie by setting its value to an empty string and setting the expiry date in the past.
You must specify a path
for the cookie. In most cases you should explicitly set path: '/'
to make the cookie available throughout your app. You can use relative paths, or set path: ''
to make the cookie only available on the current path and its children
delete('sessionid', { path: string
Specifies the value for the
{@link
https://tools.ietf.org/html/rfc6265#section-5.2.4 Path
Set-Cookie
attribute
}
.
By default, the path is considered the “default path”.
path: '/' });
event: RequestEvent<Record<string, any>, string | null>
event.RequestEvent<Params extends Partial<Record<string, string>> = Partial<Record<string, string>>, RouteId extends string | null = string | null>.locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user: {
name: string;
} | null
user = null;
}
};
import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad, type Actions = {
[x: string]: Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>
event) => {
return {
user: {
name: string;
} | null
user: event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>
event.RequestEvent<Record<string, any>, string | null>.locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user: {
name: string;
} | null
user
};
};
export const const actions: {
logout: (event: RequestEvent<Record<string, any>, string | null>) => Promise<void>;
}
actions = {
logout: (event: RequestEvent<Record<string, any>, string | null>) => Promise<void>
logout: async (event: RequestEvent<Record<string, any>, string | null>
event) => {
event: RequestEvent<Record<string, any>, string | null>
event.RequestEvent<Record<string, any>, string | null>.cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.delete: (name: string, opts: CookieSerializeOptions & {
path: string;
}) => void
Deletes a cookie by setting its value to an empty string and setting the expiry date in the past.
You must specify a path
for the cookie. In most cases you should explicitly set path: '/'
to make the cookie available throughout your app. You can use relative paths, or set path: ''
to make the cookie only available on the current path and its children
delete('sessionid', { path: string
Specifies the value for the
{@link
https://tools.ietf.org/html/rfc6265#section-5.2.4 Path
Set-Cookie
attribute
}
.
By default, the path is considered the “default path”.
path: '/' });
event: RequestEvent<Record<string, any>, string | null>
event.RequestEvent<Params extends Partial<Record<string, string>> = Partial<Record<string, string>>, RouteId extends string | null = string | null>.locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user: {
name: string;
} | null
user = null;
}
} satisfies type Actions = {
[x: string]: Action<Record<string, any>, void | Record<string, any>, string | null>;
}
Actions;
Amélioration progressive
Dans les sections précédentes, nous avons construit une action /login
qui fonctionne sans
JavaScript côté client — aucun fetch
n’a
été impliqué. C’est super, mais lorsque JavaScript est disponible, nous pouvons améliorer
progressivement nos interactions de formulaire pour fournir une meilleure expérience utilisateur.
use:enhance
La manière la plus simple d’améliorer un formulaire progressivement est d’ajouter l’action
use:action
:
<script>
import { enhance } from '$app/forms';
/** @type {import('./$types').PageProps} */
let { form } = $props();
</script>
<form method="POST" use:enhance>
<script lang="ts">
import { enhance } from '$app/forms';
import type { PageProps } from './$types';
let { form }: PageProps = $props();
</script>
<form method="POST" use:enhance>
use:enhance
peut uniquement être utilisé avec des formulaires qui ontmethod="POST"
et pointent vers des actions définies dans un fichier+page.server.js
. Cela ne fonctionnera pas avecmethod="GET"
, qui est le fonctionnement par défaut pour des formulaires sans méthode précisée. Utiliseruse:enhance
sur des formulaires sansmethod="POST"
ou cibler un endpoint+server.js
va provoquer une erreur.
Oui, il peut y avoir de la confusion entre l’action
enhance
et<form action>
, qui sont toutes les deux appelées “action”. Cette documentation est pleine d’actions. Désolé.
Sans argument, use:enhance
va émuler le comportement natif du navigateur, simplement sans le
rechargement complet de la page. Plus précisément, cela va :
- mettre à jour la propriété
form
, ainsi quepage.form
etpage.status
lors d’une réponse réussie ou invalide, mais uniquement si l’action est sur la même page que celle depuis laquelle vous soumettez. Par exemple, si vous formulaire ressemble à<form action="/somewhere/else" ..>
, la propriétéform
et l’étatpage.form
ne seront pas mis à jour. En effet, la soumission native d’un formulaire vous redirige vers la page sur laquelle l’action est définie. Si vous souhaitez tout de même les mettre à jour, vous devez utiliserapplyAction
- réinitialiser l’élément
<form>
- invalider toutes les données avec
invalidateAll
si la réponse est réussie - appeler
goto
si la réponse est une redirection - afficher la frontière d’erreur
+error
la plus proche si une erreur se produit - réinitialiser le focus sur l’élément approprié
Personnaliser use:enhance
Pour personnaliser le comportement, vous pouvez fournir une SubmitFunction
qui sera exécutée
immédiatement avant la soumission du formulaire, et (optionnellement) renvoyer un callback qui
fournira une ActionResult
. Notez que si vous renvoyez un callback, le comportement par défaut
mentionné plus haut sera ignoré. Pour récupérer ce comportement, vous devez exécuter update
.
<form
method="POST"
use:enhance={({ formElement, formData, action, cancel, submitter }) => {
// `formElement` est l'élément `<form>`
// `formData` est son objet `FormData` qui est sur le point d'être soumis
// `action` est l'URL vers laquelle le formulaire pointe
// exécuter `cancel()` va empêcher la soumission
// `submitter` est l'élément `HTMLElement` qui a provoqué la soumission du formulaire
return async ({ result, update }) => {
// `result` est un objet `ActionResult`
// `update` est une fonction qui déclenche la logique qui aurait été exécutée par défaut si ce
// callback n'avait pas été défini
};
}}
>
Vous pouvez utiliser ces fonctions pour afficher et cacher des éléments d’interface de chargement, entre autres.
Si vous renvoyez un callback, vous pourriez avoir besoin de reproduire en partie le comportement par
défaut de use:enhance
, mais sans invalider toutes les données lors d’une réponse réussie. Vous
pouvez faire cela grâce à applyAction
:
<script>
import { enhance, applyAction } from '$app/forms';
/** @type {import('./$types').PageProps} */
let { form } = $props();
</script>
<form
method="POST"
use:enhance={({ formElement, formData, action, cancel }) => {
return async ({ result }) => {
// `result` est un objet `ActionResult`
if (result.type === 'redirect') {
goto(result.location);
} else {
await applyAction(result);
}
};
}}
>
<script lang="ts">
import { enhance, applyAction } from '$app/forms';
import type { PageProps } from './$types';
let { form }: PageProps = $props();
</script>
<form
method="POST"
use:enhance={({ formElement, formData, action, cancel }) => {
return async ({ result }) => {
// `result` est un objet `ActionResult`
if (result.type === 'redirect') {
goto(result.location);
} else {
await applyAction(result);
}
};
}}
>
Le comportement de applyAction(result)
dépend de result.type
:
success
,failure
— définitpage.status
en tant queresult.status
et met à jourform
etpage.form
en tant queresult.data
(indépendamment de la source de soumission, à la différence duupdate
venant deenhance
)redirect
— exécutegoto(result.location, { invalidateAll: true })
error
— affiche la frontière+error
la plus proche en utilisantresult.error
Dans tous les cas, le focus sera réinitialisé.
Gestionnaire personnalisé d’évènement [VO]Custom event listener
Nous pouvons également implémenter de l’amélioration progressive nous-même, sans use:enhance
, avec
un gestionnaire d’évènement normal sur l’élément <form>
:
<script>
import { invalidateAll, goto } from '$app/navigation';
import { applyAction, deserialize } from '$app/forms';
/** @type {import('./$types').PageProps} */
let { form } = $props();
/** @param {SubmitEvent & { currentTarget: EventTarget & HTMLFormElement}} event */
async function handleSubmit(event) {
event.preventDefault();
const data = new FormData(event.currentTarget);
const response = await fetch(event.currentTarget.action, {
method: 'POST',
body: data
});
/** @type {import('@sveltejs/kit').ActionResult} */
const result = deserialize(await response.text());
if (result.type === 'success') {
// ré-exécute toutes les fonctions `load`, en cas de succès
await invalidateAll();
}
applyAction(result);
}
</script>
<form method="POST" onsubmit={handleSubmit}>
<!-- contenu -->
</form>
<script lang="ts">
import { invalidateAll, goto } from '$app/navigation';
import { applyAction, deserialize } from '$app/forms';
import type { PageProps } from './$types';
import type { ActionResult } from '@sveltejs/kit';
let { form }: PageProps = $props();
async function handleSubmit(event: SubmitEvent & { currentTarget: EventTarget & HTMLFormElement}) {
event.preventDefault();
const data = new FormData(event.currentTarget);
const response = await fetch(event.currentTarget.action, {
method: 'POST',
body: data
});
const result: ActionResult = deserialize(await response.text());
if (result.type === 'success') {
// ré-exécute toutes les fonctions `load`, en cas de succès
await invalidateAll();
}
applyAction(result);
}
</script>
<form method="POST" onsubmit={handleSubmit}>
<!-- contenu -->
</form>
Notez que vous avez besoin de deserialize
la réponse avant de la traiter en utilisant la méthode
correspondante importée depuis $app/forms
. JSON.parse()
ne suffit pas car les actions de
formulaires — comme les fonctions load
— supportent également le renvoi d’objets Date
ou
BigInt
.
Si vous avez un fichier +server.js
associé à votre +page.server.js
, les requêtes fetch
vont y
être dirigées par défaut. Si vous souhaitez envoyer une requête POST
à une action de
+page.server.js
, utilisez l’en-tête personnalisée x-sveltekit-action
:
const const response: Response
response = await function fetch(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response> (+1 overload)
fetch(this.action, {
RequestInit.method?: string | undefined
A string to set request’s method.
method: 'POST',
RequestInit.body?: BodyInit | null | undefined
A BodyInit object or null to set request’s body.
body: data,
RequestInit.headers?: HeadersInit | undefined
A Headers object, an object literal, or an array of two-item arrays to set request’s headers.
headers: {
'x-sveltekit-action': 'true'
}
});
Alternatives
Les actions de formulaire sont la méthode recommandée pour envoyer des données au serveur,
puisqu’elles peuvent être améliorées progressivement, mais vous pouvez également utiliser des
fichiers +server.js
pour exposer (par exemple) une API JSON. Voici ce à quoi une
telle interaction pourrait ressembler :
<script>
function rerun() {
fetch('/api/ci', {
method: 'POST'
});
}
</script>
<button onclick={rerun}>Relancer la CI</button>
<script lang="ts">
function rerun() {
fetch('/api/ci', {
method: 'POST'
});
}
</script>
<button onclick={rerun}>Relancer la CI</button>
/** @type {import('./$types').RequestHandler} */
export function function POST(): void
POST() {
// faire quelque chose
}
import type { type RequestHandler = (event: Kit.RequestEvent<Record<string, any>, string | null>) => MaybePromise<Response>
type RequestHandler = (event: Kit.RequestEvent<Record<string, any>, string | null>) => MaybePromise<Response>
RequestHandler } from './$types';
export const const POST: RequestHandler
POST: type RequestHandler = (event: Kit.RequestEvent<Record<string, any>, string | null>) => MaybePromise<Response>
type RequestHandler = (event: Kit.RequestEvent<Record<string, any>, string | null>) => MaybePromise<Response>
RequestHandler = () => {
// faire quelque chose
};
GET vs POST
Comme nous venons de le voir, pour invoquer une action de formulaire, vous devez utiliser
method="POST"
.
Certains formulaires n’ont pas besoin d’utiliser POST
pour envoyer des données au serveur — les
inputs de recherche par exemple. Pour ces cas-là, vous pouvez utiliser method="GET"
(ou de manière
équivalente, aucune method
), et SvelteKit va traiter ces requêtes comme si elles venaient
d’éléments <a>
, utilisant le routeur client plutôt qu’une navigation impliquant le rechargement
complet de la page :
<form action="/search">
<label>
Rechercher
<input name="q">
</label>
</form>
Soumettre ce formulaire va déclencher une navigation vers /search?q=...
et invoquer votre fonction
load
, mais ne va invoquer aucune action. Comme pour les éléments <a>
, vous pouvez définir les
attributs
data-sveltekit-reload
,
data-sveltekit-replacestate
,
data-sveltekit-keepfocus
et
data-sveltekit-noscroll
sur l’élément <form>
pour
contrôler le comportement du routeur.
Sur le même sujet
Modifier cette page sur Github llms.txt