Композиция сложных форм

Carbon Components Svelte предоставляет мощный набор инструментов для создания интерактивных и доступных пользовательских интерфейсов. Основная цель при работе с формами — обеспечить структурированность, повторное использование компонентов и корректное управление состояниями.

Контейнеры форм

Для организации сложных форм используется компонент Form и его вспомогательные контейнеры:

<Form on:submit="{handleSubmit}">
  <FormGroup legendText="Основная информация">
    <TextInput labelText="Имя" bind:value="{name}" />
    <TextInput labelText="Фамилия" bind:value="{surname}" />
  </FormGroup>
  <FormGroup legendText="Контакты">
    <EmailInput labelText="Электронная почта" bind:value="{email}" />
    <TelephoneInput labelText="Телефон" bind:value="{phone}" />
  </FormGroup>
  <Button type="submit">Отправить</Button>
</Form>
  • Form — основной контейнер формы, обеспечивает обработку событий submit.
  • FormGroup — логическая группировка полей с легендой (legendText) для улучшения визуальной иерархии.
  • TextInput, EmailInput, TelephoneInput — базовые элементы ввода, поддерживающие двустороннюю привязку через bind:value.

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

Работа с состояниями

Carbon Components Svelte поддерживает несколько типов состояний:

  • Valid — корректное заполнение поля.
  • Invalid — ошибка валидации.
  • Disabled — поле недоступно для редактирования.
  • Readonly — поле доступно только для чтения.

Пример управления состояниями через свойства компонента:

<TextInput
  labelText="Имя пользователя"
  bind:value="{username}"
  invalid="{!isValidUsername}"
  invalidText="Имя пользователя должно содержать не менее 3 символов"
/>
  • invalid — принимает булево значение, включающее отображение ошибки.
  • invalidText — текст ошибки, выводимый под полем.

Компоновка с сеткой

Для сложных форм, где требуется адаптивное размещение элементов, применяется Grid:

<Grid>
  <Column sm="4">
    <TextInput labelText="Город" bind:value="{city}" />
  </Column>
  <Column sm="4">
    <TextInput labelText="Регион" bind:value="{region}" />
  </Column>
  <Column sm="4">
    <TextInput labelText="Почтовый индекс" bind:value="{zip}" />
  </Column>
</Grid>
  • Grid и Column обеспечивают отзывчивость интерфейса.
  • Размер колонки (sm="4") задаёт ширину в 4/12 части контейнера на малых экранах. Можно комбинировать md и lg для адаптивности на средних и больших экранах.

Составные поля

Для сложных форм часто требуются комбинированные элементы:

  • Dropdown + TextInput: позволяет выбрать тип значения и ввести конкретное значение.
  • Toggle + Input: включение или отключение определенного блока ввода.
  • DatePicker + TimePicker: выбор даты и времени для события.

Пример комбинированного поля:

<FormGroup legendText="Выбор даты и времени">
  <DatePicker bind:value="{selectedDate}" dateFormat="m/d/Y" />
  <TimePicker bind:value="{selectedTime}" />
</FormGroup>

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

Валидация сложных форм

В Carbon Components Svelte валидация может быть локальной для компонента или глобальной для формы.

Локальная валидация:

<TextInput
  labelText="Пароль"
  bind:value="{password}"
  invalid="{password.length < 8}"
  invalidText="Пароль должен быть не менее 8 символов"
/>

Глобальная валидация:

function handleSubmit(event) {
  event.preventDefault();
  const isFormValid = name && email && password.length >= 8;
  if (!isFormValid) {
    alert("Форма содержит ошибки");
  } else {
    console.log("Данные формы:", { name, email, password });
  }
}

Динамическое добавление и удаление полей

Сложные формы часто требуют возможности добавления элементов на лету. Это реализуется через массивы и #each:

{#each contacts as contact, index}
  <FormGroup legendText="Контакт">
    <TextInput
      labelText="Имя"
      bind:value="{contact.name}"
    />
    <TextInput
      labelText="Телефон"
      bind:value="{contact.phone}"
    />
    <Button kind="secondary" on:click="{() => removeContact(index)}">Удалить</Button>
  </FormGroup>
{/each}

<Button on:click="{addContact}">Добавить контакт</Button>
  • addContact добавляет новый объект в массив contacts.
  • removeContact(index) удаляет элемент по индексу.
  • Это позволяет строить гибкие формы с переменным числом полей.

Оптимизация производительности

При работе с большими формами важно минимизировать количество реактивных вычислений:

  • Использовать локальные состояния в дочерних компонентах вместо глобального store, если данные не требуются вне формы.
  • Применять bind:this для прямого обращения к DOM элементам при необходимости, чтобы избежать лишнего ререндеринга.

Доступность

Все компоненты Carbon поддерживают ARIA-атрибуты, обеспечивая доступность для скринридеров:

  • aria-label и aria-describedby автоматически управляются компонентами.
  • FormGroup и legendText помогают скринридерам понять логическую группировку полей.
  • Использование компонентов Toggle, RadioButtonGroup, CheckboxGroup гарантирует корректное взаимодействие с клавиатурой.

Итоговая структура сложной формы

  1. Form — контейнер для всей формы.
  2. FormGroup — логическая группировка элементов.
  3. Grid/Column — управление компоновкой и адаптивностью.
  4. Input-компоненты — текстовые, числовые, почтовые, специальные.
  5. Комбинированные поля — Dropdown, Toggle, Date/TimePicker.
  6. Динамические массивы полей — добавление и удаление элементов через #each.
  7. Валидация и состояние — локальная и глобальная.
  8. Доступность и ARIA — встроенная поддержка Carbon.

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