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

Radix UI предоставляет низкоуровневые, полностью управляемые компоненты пользовательского интерфейса для React, которые можно использовать для построения сложных интерфейсов без ограничения дизайна. Одним из ключевых аспектов взаимодействия с формами является интеграция этих компонентов с валидационными библиотеками, такими как React Hook Form, Formik, Yup или Zod.

Основные принципы интеграции

Radix UI ориентирован на контроль состояния через пропсы и слоты. Это означает, что для корректной интеграции с валидационными библиотеками необходимо:

  1. Декларировать состояние поля через value и onChange.
  2. Синхронизировать ошибки валидации с визуальными индикаторами.
  3. Использовать элементы Radix UI как контролируемые компоненты для обеспечения полной совместимости с формами.

Пример типового подхода:

import { useForm } from "react-hook-form";
import * as RadixInput from "@radix-ui/react-input";

function FormExample() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  
  const onSub mit = (data) => console.log(data);
  
  return (
    <form onSub mit={handleSubmit(onSubmit)}>
      <RadixInput.Root>
        <RadixInput.Input
          {...register("username", { required: "Поле обязательно" })}
          placeholder="Введите имя"
        />
        {errors.username && <span>{errors.username.message}</span>}
      </RadixInput.Root>
      <button type="submit">Отправить</button>
    </form>
  );
}

В этом примере RadixInput.Input выступает контролируемым компонентом, который напрямую взаимодействует с React Hook Form. Ошибки валидации отображаются через условный рендеринг.

Работа с кастомными компонентами

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

Пример для кастомного селекта:

import * as Sel ect from "@radix-ui/react-select";
import { useForm, Controller } fr om "react-hook-form";

function CustomSelectForm() {
  const { control, handleSubmit, formState: { errors } } = useForm();
  
  const onSub mit = (data) => console.log(data);
  
  return (
    <form onSub mit={handleSubmit(onSubmit)}>
      <Controller
        name="fruit"
        control={control}
        rules={{ required: "Выберите фрукт" }}
        render={({ field }) => (
          <Sel ect.Root onValueCha nge={field.onChange} value={field.value}>
            <Sel ect.Trigger>
              <Sel ect.Value placeholder="Выберите фрукт" />
            </Sel ect.Trigger>
            <Sel ect.Content>
              <Select.Item value="apple">Яблоко</Select.Item>
              <Select.Item value="orange">Апельсин</Select.Item>
              <Select.Item value="banana">Банан</Select.Item>
            </Select.Content>
          </Select.Root>
        )}
      />
      {errors.fruit && <span>{errors.fruit.message}</span>}
      <button type="submit">Отправить</button>
    </form>
  );
}

Использование Controller из React Hook Form позволяет обернуть сложные компоненты Radix UI, которые не предоставляют стандартного события onChange на уровне DOM, и корректно подключить их к валидации.

Валидация схемами Yup и Zod

Для более сложной валидации рекомендуется использовать схемы Yup или Zod. Пример интеграции с Yup:

import { useForm } fr om "react-hook-form";
import { yupResolver } fr om "@hookform/resolvers/yup";
import * as yup fr om "yup";
import * as RadixInput fr om "@radix-ui/react-input";

const schema = yup.object({
  email: yup.string().email("Неверный формат email").required("Обязательное поле"),
});

function EmailForm() {
  const { register, handleSubmit, formState: { errors } } = useForm({
    resolver: yupResolver(schema),
  });

  const onSub mit = (data) => console.log(data);

  return (
    <form onSub mit={handleSubmit(onSubmit)}>
      <RadixInput.Root>
        <RadixInput.Input {...register("email")} placeholder="Введите email" />
        {errors.email && <span>{errors.email.message}</span>}
      </RadixInput.Root>
      <button type="submit">Отправить</button>
    </form>
  );
}

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

Отображение ошибок и визуальные подсказки

Radix UI предоставляет возможность создавать собственные тултипы, тулбары и индикаторы для ошибок. Важным моментом является синхронизация состояния ошибки с визуальным компонентом:

import * as Tooltip fr om "@radix-ui/react-tooltip";

<Tooltip.Root>
  <Tooltip.Trigger asChild>
    <RadixInput.Input {...register("password")} placeholder="Пароль" />
  </Tooltip.Trigger>
  {errors.password && (
    <Tooltip.Content side="right">
      {errors.password.message}
    </Tooltip.Content>
  )}
</Tooltip.Root>

Такой подход обеспечивает единый стиль отображения ошибок без использования стандартных HTML-элементов <span> или <div> для текста ошибки, что повышает визуальную согласованность интерфейса.

Итоговые рекомендации

  • Использовать контролируемые компоненты Radix UI для точного контроля состояния.
  • Для сложных компонентов применять Controller из React Hook Form.
  • Валидационные схемы Yup или Zod позволяют централизованно управлять правилами и упрощают масштабирование форм.
  • Ошибки валидации рекомендуется отображать через компоненты Radix UI, что позволяет сохранять единый стиль интерфейса.
  • Тщательно тестировать интеграцию, особенно для динамически создаваемых компонентов, чтобы избежать рассинхронизации состояния формы и визуальных индикаторов.

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