Формы и валидация с внешними библиотеками

Для работы с компонентами форм Carbon в проекте на Svelte необходимо установить библиотеку через npm:

npm install carbon-components-svelte

Импорт компонентов осуществляется по мере необходимости:

<script>
  import { TextInput, Button, Checkbox, Form, FormItem } from 'carbon-components-svelte';
</script>

Каждый компонент поддерживает стили Carbon по умолчанию, а также позволяет настраивать темы, размеры и состояния ошибок через свойства.


Основные компоненты форм

TextInput — текстовое поле с поддержкой состояния ошибки, подсказок и обязательных полей:

<TextInput
  labelText="Имя пользователя"
  placeholder="Введите имя"
  helperText="Минимум 3 символа"
  invalid={usernameError}
  invalidText="Имя слишком короткое"
/>
  • labelText — метка поля
  • placeholder — подсказка внутри поля
  • helperText — вспомогательная информация
  • invalid и invalidText — управление состоянием ошибки

Checkbox — флажок, поддерживает одиночный и групповой выбор:

<Checkbox
  labelText="Согласен с условиями"
  checked={agreement}
/>

Button — кнопка для отправки формы:

<Button type="submit">Отправить</Button>

Form и FormItem — структурируют форму и её элементы, обеспечивая правильное размещение компонентов и их связку с доступностью (ARIA):

<Form on:submit|preventDefault={handleSubmit}>
  <FormItem>
    <TextInput labelText="Email" />
  </FormItem>
  <FormItem>
    <Button type="submit">Отправить</Button>
  </FormItem>
</Form>

Валидация с использованием внешних библиотек

В проектах на Svelte часто применяют Yup, Zod или Superstruct для схемной валидации данных формы.

Валидация с Yup

Установка:

npm install yup

Создание схемы и интеграция с компонентами:

import * as yup from 'yup';

const schema = yup.object({
  username: yup.string().min(3, 'Имя должно быть не короче 3 символов').required('Обязательное поле'),
  email: yup.string().email('Неверный формат email').required('Обязательное поле'),
  agree: yup.boolean().oneOf([true], 'Необходимо согласие')
});

let formData = {
  username: '',
  email: '',
  agree: false
};

let errors = {};

Функция валидации:

async function validateForm() {
  try {
    await schema.validate(formData, { abortEarly: false });
    errors = {};
    return true;
  } catch (err) {
    errors = {};
    err.inner.forEach(e => {
      errors[e.path] = e.message;
    });
    return false;
  }
}

Привязка ошибок к компонентам:

<TextInput
  labelText="Имя пользователя"
  bind:value={formData.username}
  invalid={errors.username}
  invalidText={errors.username}
/>

<TextInput
  labelText="Email"
  bind:value={formData.email}
  invalid={errors.email}
  invalidText={errors.email}
/>

<Checkbox
  labelText="Согласен с условиями"
  bind:checked={formData.agree}
  invalid={errors.agree}
  invalidText={errors.agree}
/>

Обработка отправки:

async function handleSubmit() {
  const isValid = await validateForm();
  if (isValid) {
    console.log('Форма отправлена', formData);
  }
}

Валидация с Zod

Zod позволяет строить строгие схемы с автоматическим типизированием.

npm install zod

Пример схемы и валидации:

import { z } from 'zod';

const schema = z.object({
  username: z.string().min(3, { message: "Имя должно быть не короче 3 символов" }),
  email: z.string().email({ message: "Неверный формат email" }),
  agree: z.boolean().refine(val => val === true, { message: "Необходимо согласие" })
});

let formData = { username: '', email: '', agree: false };
let errors = {};

function validateForm() {
  const result = schema.safeParse(formData);
  if (!result.success) {
    errors = {};
    result.error.errors.forEach(e => {
      errors[e.path[0]] = e.message;
    });
    return false;
  }
  errors = {};
  return true;
}

Привязка и обработка идентична примеру с Yup.


Обработка динамических форм

Для форм с динамическими полями удобно использовать каждое поле как отдельный компонент, передавая ему привязку к объекту данных и ошибкам:

{#each fields as field}
  <FormItem>
    <TextInput
      labelText={field.label}
      bind:value={formData[field.name]}
      invalid={errors[field.name]}
      invalidText={errors[field.name]}
    />
  </FormItem>
{/each}
  • fields — массив конфигурации: { name, label }
  • formData и errors автоматически поддерживают новые поля

Стилизация и темы

Carbon Components Svelte поддерживает темы Carbon через CSS-переменные и модификаторы:

<TextInput
  labelText="Имя пользователя"
  class="bx--text-input--light"
/>

Доступные состояния:

  • invalid — ошибка
  • disabled — недоступно
  • helperText — подсказка под полем

Можно комбинировать с глобальной темой:

:global(.bx--text-input--light) {
  background-color: #f4f4f4;
}

Интеграция с Svelte Stores

Для крупных приложений удобно хранить данные формы в Svelte Stores:

import { writable } from 'svelte/store';

export const formData = writable({
  username: '',
  email: '',
  agree: false
});

export const errors = writable({});

Привязка компонентов к store через bind:value={$formData.username} обеспечивает реактивность на изменение данных формы из любых частей приложения.


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