Разработка формы с динамическими полями на сайте

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

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка формы с динамическими полями на сайте
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Разработка формы с динамическими полями на сайте

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

Реализация через React Hook Form useFieldArray

import { useForm, useFieldArray, Controller } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';

const passengerSchema = z.object({
  firstName: z.string().min(2),
  lastName:  z.string().min(2),
  birthDate: z.string(),
  passport:  z.string().regex(/^\d{4}\s\d{6}$/),
});

const formSchema = z.object({
  passengers: z.array(passengerSchema).min(1).max(9),
});

type FormValues = z.infer<typeof formSchema>;

export function PassengersForm() {
  const { control, register, handleSubmit, formState: { errors } } = useForm<FormValues>({
    resolver: zodResolver(formSchema),
    defaultValues: { passengers: [{}] },
  });

  const { fields, append, remove, move } = useFieldArray({
    control,
    name: 'passengers',
  });

  return (
    <form onSubmit={handleSubmit(console.log)}>
      <div className="space-y-4">
        {fields.map((field, index) => (
          <div key={field.id} className="border rounded-xl p-4 relative">
            <div className="flex items-center justify-between mb-3">
              <h3 className="font-medium">Пассажир {index + 1}</h3>
              {fields.length > 1 && (
                <button
                  type="button"
                  onClick={() => remove(index)}
                  className="text-red-500 text-sm hover:text-red-700"
                >
                  Удалить
                </button>
              )}
            </div>

            <div className="grid grid-cols-2 gap-3">
              <div>
                <label className="block text-sm mb-1">Имя</label>
                <input
                  {...register(`passengers.${index}.firstName`)}
                  className="input-field"
                />
                {errors.passengers?.[index]?.firstName && (
                  <p className="text-red-500 text-xs mt-1">
                    {errors.passengers[index].firstName?.message}
                  </p>
                )}
              </div>

              <div>
                <label className="block text-sm mb-1">Фамилия</label>
                <input {...register(`passengers.${index}.lastName`)} className="input-field" />
              </div>

              <div>
                <label className="block text-sm mb-1">Паспорт</label>
                <input
                  {...register(`passengers.${index}.passport`)}
                  placeholder="1234 567890"
                  className="input-field"
                />
              </div>
            </div>
          </div>
        ))}
      </div>

      {fields.length < 9 && (
        <button
          type="button"
          onClick={() => append({})}
          className="btn-secondary mt-4 w-full"
        >
          + Добавить пассажира
        </button>
      )}

      <button type="submit" className="btn-primary mt-4 w-full">
        Продолжить
      </button>
    </form>
  );
}

Drag-and-drop сортировка

Для форм, где порядок элементов важен (список товаров в заказе, приоритеты задач):

import { DndContext, closestCenter } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';

function SortableFieldItem({ field, index, onRemove }: SortableItemProps) {
  const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: field.id });

  return (
    <div ref={setNodeRef} style={{ transform: CSS.Transform.toString(transform), transition }}>
      <div {...attributes} {...listeners} className="cursor-grab p-1">⠿</div>
      {/* поля элемента */}
    </div>
  );
}

// В основном компоненте:
function handleDragEnd(event) {
  const { active, over } = event;
  if (active.id !== over.id) {
    const from = fields.findIndex(f => f.id === active.id);
    const to   = fields.findIndex(f => f.id === over.id);
    move(from, to);
  }
}

Сроки

Форма с динамическими полями, добавлением/удалением и валидацией: 2–4 рабочих дня.