Нативные формы в SvelteKit строятся вокруг стандартного
HTML-механизма <form>, но расширяются возможностями
фреймворка: серверные обработчики, прогрессивное улучшение, реактивность
и управление состоянием без сторонних библиотек. Основной принцип —
использование встроенного поведения браузера с постепенным добавлением
клиентской логики.
Ключевое отличие от SPA-подхода заключается в том, что форма может корректно работать даже без JavaScript. При этом при наличии JS включается механизм перехвата и оптимизации запросов.
Форма отправляет данные на сервер через POST, где они
обрабатываются в +page.server.js или
+server.js.
<form method="POST">
<input name="email" type="email" required />
<button type="submit">Отправить</button>
</form>
Серверная логика:
export const actions = {
default: async ({ request }) => {
const data = await request.formData();
const email = data.get('email');
if (!email) {
return { error: 'Email обязателен' };
}
return { success: true };
}
};
Особенности:
formData() — стандартный Web APIactions через именованные
обработчикиРезультат выполнения action доступен через
form в компоненте страницы:
<script>
export let form;
</script>
{#if form?.error}
<p>{form.error}</p>
{/if}
{#if form?.success}
<p>Успешно отправлено</p>
{/if}
Состояние формы:
undefined — форма не отправляласьuse:enhance)SvelteKit предоставляет директиву use:enhance, которая
превращает стандартную форму в SPA-поведение:
<script>
import { enhance } from '$app/forms';
</script>
<form method="POST" use:enhance>
<input name="name" />
<button>Сохранить</button>
</form>
Что происходит:
fetchДополнительно можно кастомизировать:
<form method="POST" use:enhance={({ result }) => {
if (result.type === 'success') {
console.log('Успех');
}
}}>
Используются стандартные HTML-атрибуты:
<input type="email" required />
<input minlength="6" />
if (!email.includes('@')) {
return { error: 'Некорректный email' };
}
Важно:
После ошибки форма может потерять введённые значения. Для восстановления:
return {
error: 'Ошибка',
values: { email }
};
В компоненте:
<input name="email" value={form?.values?.email ?? ''} />
Можно определять несколько обработчиков:
export const actions = {
login: async ({ request }) => { ... },
register: async ({ request }) => { ... }
};
В форме:
<form method="POST">
<button name="intent" value="login">Войти</button>
<button name="intent" value="register">Регистрация</button>
</form>
Можно выбрасывать ошибки:
import { fail } from '@sveltejs/kit';
return fail(400, {
error: 'Неверные данные'
});
Особенности:
fail сохраняет данные формыimport { redirect } from '@sveltejs/kit';
throw redirect(303, '/dashboard');
Используется:
<form method="POST" enctype="multipart/form-data">
<input type="file" name="avatar" />
</form>
На сервере:
const file = data.get('avatar');
Особенности:
File объект содержит имя, размер, типИногда требуется полный контроль:
<script>
async function submitForm(e) {
e.preventDefault();
const formData = new FormData(e.target);
const res = await fetch('/endpoint', {
method: 'POST',
body: formData
});
const result = await res.json();
}
</script>
<form on:submit={submitForm}>
С use:enhance:
<script>
import { enhance } from '$app/forms';
let loading = false;
</script>
<form method="POST" use:enhance={() => {
loading = true;
return async ({ upd ate }) => {
await update();
loading = false;
};
}}>
<button disabled={loading}>
{loading ? 'Загрузка...' : 'Отправить'}
</button>
</form>
Проблема:
Решения:
export const actions = {
login: async ({ request, cookies }) => {
cookies.se t('session', 'token', {
path: '/',
httpOnly: true
});
return { success: true };
}
};
При использовании UI-библиотек (например, кастомных компонентов):
<Input name="email" bind:value />
Важно:
namevalueИначе formData не получит данные.
Можно генерировать поля:
{#each fields as field}
<input name={field.name} />
{/each}
Сервер:
for (const [key, value] of data.entries()) {
console.log(key, value);
}
Ключевые аспекты:
HTML не поддерживает вложенные формы. Решения:
use:enhance(({ form, data, cancel }) => {
if (!form.checkValidity()) {
cancel();
}
});
Позволяет:
<form method="GET">
<input name="q" />
</form>
Результат:
После отправки формы можно обновить данные:
export const load = async ({ fetch }) => {
const res = await fetch('/api/data');
return { data: await res.json() };
};
enhance автоматически вызывает обновление.
После ошибки:
<input autofocus />
или программно:
name у inputmethodenhanceСостояние хранится:
sessionStorageКаждый шаг — отдельная форма или состояние.
Преимущества нативного подхода:
Недостатки:
Можно добавлять обработку:
export const handle = async ({ event, resolve }) => {
// логика перед формой
return resolve(event);
};
Форма может работать напрямую с API:
await fetch('/api/submit', { method: 'POST' });
Или через actions — предпочтительный способ.
import { writable } from 'svelte/store';
export const formState = writable({});
Используется для сложных форм.
SvelteKit реализует формы как:
Это позволяет строить масштабируемые, быстрые и устойчивые интерфейсы без избыточных зависимостей.