Form и валидация с superforms

Библиотека Superforms предоставляет мощный и удобный способ работы с формами в SvelteKit, включая управление состоянием формы, валидацию данных и обработку ошибок на клиенте и сервере одновременно. Она интегрируется с Zod, что позволяет задавать строгие схемы валидации и минимизировать дублирование логики.


Установка и настройка

Для начала необходимо установить зависимости:

npm install superforms zod

После установки подключение Superforms осуществляется через load функции в SvelteKit. Например:

// src/routes/contact/+page.server.js
import { superValidate } from 'superforms';
import { z } from 'zod';

const contactSchema = z.object({
    name: z.string().min(2, "Имя должно содержать минимум 2 символа"),
    email: z.string().email("Неверный формат email"),
    message: z.string().min(10, "Сообщение должно быть не короче 10 символов")
});

export async function load() {
    const form = await superValidate(contactSchema);
    return { form };
}

export const actions = {
    default: async ({ request }) => {
        const form = await superValidate(request, contactSchema);
        if (!form.valid) return { form };
        // Обработка данных формы, например сохранение в БД
        return { form, success: true };
    }
};

Здесь ключевое — использование superValidate, которое обеспечивает:

  • Автоматическую генерацию состояния формы
  • Проверку валидности данных на сервере
  • Подготовку объекта, который легко использовать на клиенте

Интеграция формы в компонент Svelte

После создания схемы и загрузки состояния формы её можно интегрировать в компонент Svelte следующим образом:

<script lang="ts">
    import { form } from '$page.data';
    import { formAction } from 'superforms';
</script>

<form use:for mAction={form}>
    <label>
        Имя
        <input type="text" name="name" bind:value={form.data.name} />
        {#if form.errors.name}
            <span class="error">{form.errors.name}</span>
        {/if}
    </label>

    <label>
        Email
        <input type="email" name="email" bind:value={form.data.email} />
        {#if form.errors.email}
            <span class="error">{form.errors.email}</span>
        {/if}
    </label>

    <label>
        Сообщение
        <textarea name="message" bind:value={form.data.message}></textarea>
        {#if form.errors.message}
            <span class="error">{form.errors.message}</span>
        {/if}
    </label>

    <button type="submit" disabled={!form.valid}>Отправить</button>

    {#if form.success}
        <p class="success">Форма успешно отправлена!</p>
    {/if}
</form>

Особенности:

  • bind:value={form.data.field} синхронизирует состояние формы с объектом данных
  • form.errors.field отображает ошибки валидации рядом с полем
  • form.valid и form.success позволяют управлять доступностью кнопки отправки и выводом сообщений

Валидация с Zod

Superforms полностью совместим с Zod, что позволяет задавать сложные правила:

const registrationSchema = z.object({
    username: z.string().min(3, "Имя пользователя слишком короткое"),
    password: z.string().min(8, "Пароль должен быть не короче 8 символов"),
    confirmPassword: z.string()
}).refine((data) => data.password === data.confirmPassword, {
    message: "Пароли не совпадают",
    path: ["confirmPassword"]
});

Использование refine позволяет задавать кастомные проверки, такие как совпадение паролей, проверка формата телефонного номера или сложные логические условия. Все ошибки автоматически попадают в form.errors и могут быть показаны в интерфейсе.


Асинхронная валидация

Superforms поддерживает асинхронные проверки, например проверку уникальности логина через API:

import { superValidate } from 'superforms';
import { z } from 'zod';

const asyncSchema = z.object({
    username: z.string().min(3).refine(async (username) => {
        const res = await fetch(`/api/check-username?username=${username}`);
        const { available } = await res.json();
        return available;
    }, "Имя пользователя уже занято")
});

export async function load() {
    return { form: await superValidate(asyncSchema) };
}

Асинхронная валидация выполняется автоматически при отправке формы и интегрируется с form.errors.


Пользовательские компоненты формы

Superforms позволяет создавать собственные UI-компоненты, сохраняя синхронизацию с формой:

<script lang="ts">
    export let form;
    export let name;
</script>

<div class="input-wrapper">
    <slot name="label"></slot>
    <input bind:value={form.data[name]} name={name} />
    {#if form.errors[name]}
        <span class="error">{form.errors[name]}</span>
    {/if}
</div>

Использование таких компонентов упрощает поддержание единого стиля форм на всем проекте и уменьшает дублирование кода.


Дополнительные возможности

  • Сброс формы: form.reset() возвращает все поля к исходному состоянию
  • Поддержка многокомпонентных форм: один объект формы может управлять несколькими полями, разбросанными по разным компонентам
  • Серверная интеграция: возможность обрабатывать формы на сервере без лишнего дублирования валидации

Оптимизация UX

  • Использование form.valid для блокировки кнопки отправки предотвращает отправку невалидных данных
  • Вывод ошибок рядом с полями ускоряет реакцию пользователя
  • Асинхронные проверки помогают избегать конфликтов при регистрации и других критичных сценариях

Superforms в связке с Zod делает работу с формами в SvelteKit безопасной, удобной и масштабируемой, позволяя сосредоточиться на логике приложения, а не на рутинных проверках и управлении состоянием формы.