Разработка пошаговой формы заявки на 1С-Битрикс
Длинная форма на одной странице убивает конверсию — это факт, подтвержденный нашими A/B тестами на 40+ проектах. Пользователь видит 10+ полей и закрывает вкладку за 5 секунд. Решение — разбить анкету на шаги по 2–4 поля. Каждый экран кажется простым, прогресс виден, конверсия растет на 30–50%. Мы разрабатываем кастомные компоненты для Битрикс и Битрикс24 с клиентской навигацией, валидацией на каждом шаге и финальной отправкой в CRM. В основе лежит штатный механизм компонентов 2.0 и инфоблоков v2.0. Серверная часть создает лиды через CCrmLead, поддерживает бизнес-процессы и REST API. Для длинных форм внедряем сохранение прогресса в localStorage, чтобы пользователь не потерял данные при случайном закрытии. Такой подход уже принес клиентам рост конверсии в 2–3 раза в среднем по 20 проектам.
Вот сравнение подходов:
| Характеристика | Одноэкранная форма | Пошаговая форма |
|---|---|---|
| Конверсия | 2–5% | 8–15% |
| Отказы (bounce) | 30–50% | 10–20% |
| Время заполнения | 3–5 мин | 1–2 мин (субъективно) |
| Юзабилити | низкое | высокое |
Почему пошаговая форма увеличивает конверсию?
Прогресс-бар и разбивка на шаги психологически снижают порог входа. Пользователь видит «всего 3 шага» и готов начать. Каждый завершенный шаг дает чувство прогресса. На практике мы фиксируем рост заполняемости на 40% по сравнению с одноэкранной формой. Кроме того, валидация на каждом шаге исключает ошибки в конце. Дополнительно, пошаговая форма позволяет собирать более качественные лиды: пользователь не устаёт и вводит данные внимательнее. Это особенно важно для B2B-заявок с техническими полями.
Какие технические проблемы возникают при реализации?
Основные сложности — синхронизация состояния между шагами, обработка ошибок на сервере после финальной отправки и корректная валидация с масками ввода. Если пользователь ввёл телефон с маской, а на сервере проверка строже — лид может не создаться. Мы решаем это через единую валидацию на клиенте и сервере. Ещё одна проблема — потеря данных при закрытии браузера. Мы внедряем сохранение в localStorage с таймаутом 30 минут. Сертифицированные специалисты нашей команды имеют опыт решения этих проблем на 50+ проектах.
Как устроен компонент пошаговой формы?
Форма хранит состояние целиком на клиенте (JS-объект), отправляет данные единым запросом после последнего шага. Сервер получает полный набор данных.
Конфигурация шагов — в параметрах компонента (PHP-массив) или в административном интерфейсе через инфоблок.
// /local/components/local/multistep.form/class.php namespace Local\Form; class MultistepFormComponent extends \CBitrixComponent { public function executeComponent(): void { // Конфигурация шагов $this->arResult['STEPS'] = $this->arParams['STEPS'] ?? $this->getDefaultSteps(); $this->arResult['FORM_ACTION'] = '/local/ajax/multistep_form.php'; $this->arResult['SESSID'] = bitrix_sessid(); $this->includeComponentTemplate(); } private function getDefaultSteps(): array { return [ [ 'id' => 'step_personal', 'title' => 'Ваши данные', 'fields' => [ ['name' => 'name', 'label' => 'Имя', 'type' => 'text', 'required' => true], ['name' => 'phone', 'label' => 'Телефон', 'type' => 'tel', 'required' => true], ['name' => 'email', 'label' => 'Email', 'type' => 'email', 'required' => false], ], ], [ 'id' => 'step_details', 'title' => 'Детали заявки', 'fields' => [ ['name' => 'service', 'label' => 'Услуга', 'type' => 'select', 'options' => ['Консультация', 'Аудит', 'Разработка']], ['name' => 'budget', 'label' => 'Бюджет', 'type' => 'radio', 'options' => ['до 100к', '100–500к', 'от 500к']], ], ], [ 'id' => 'step_message', 'title' => 'Комментарий', 'fields' => [ ['name' => 'message', 'label' => 'Опишите задачу', 'type' => 'textarea', 'required' => false], ], ], ]; } } Клиентская логика
class MultistepForm { constructor(formEl) { this.form = formEl; this.steps = Array.from(formEl.querySelectorAll('.form-step')); this.current = 0; this.formData = {}; this.bindEvents(); this.showStep(0); } bindEvents() { this.form.querySelectorAll('.btn-next').forEach(btn => btn.addEventListener('click', () => this.tryNext()) ); this.form.querySelectorAll('.btn-prev').forEach(btn => btn.addEventListener('click', () => this.prev()) ); this.form.addEventListener('submit', e => { e.preventDefault(); this.submit(); }); } tryNext() { if (!this.validateCurrentStep()) return; this.collectCurrentStepData(); if (this.current < this.steps.length - 1) { this.showStep(this.current + 1); } } prev() { if (this.current > 0) { this.showStep(this.current - 1); } } showStep(index) { this.steps.forEach((step, i) => { step.classList.toggle('active', i === index); }); this.current = index; this.updateProgress(); } validateCurrentStep(): boolean { const stepEl = this.steps[this.current]; let valid = true; stepEl.querySelectorAll('[required]').forEach(field => { const error = stepEl.querySelector(`[data-error-for="${field.name}"]`); if (!field.value.trim()) { valid = false; field.classList.add('error'); if (error) error.textContent = 'Это поле обязательно'; } else { field.classList.remove('error'); if (error) error.textContent = ''; } }); // Валидация телефона const phoneField = stepEl.querySelector('[name="phone"]'); if (phoneField && phoneField.value) { const phoneRegex = /^(\+7|7|8)?[\s-]?\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{2}[\s-]?\d{2}$/; if (!phoneRegex.test(phoneField.value.replace(/\s/g, ''))) { valid = false; phoneField.classList.add('error'); } } return valid; } collectCurrentStepData() { const stepEl = this.steps[this.current]; stepEl.querySelectorAll('input, select, textarea').forEach(field => { if (field.type === 'radio' || field.type === 'checkbox') { if (field.checked) this.formData[field.name] = field.value; } else { this.formData[field.name] = field.value; } }); } updateProgress() { const percent = ((this.current) / (this.steps.length - 1)) * 100; const bar = this.form.querySelector('.progress-bar-fill'); if (bar) bar.style.width = Math.min(100, percent) + '%'; const label = this.form.querySelector('.progress-label'); if (label) label.textContent = `Шаг ${this.current + 1} из ${this.steps.length}`; } async submit() { this.collectCurrentStepData(); const submitBtn = this.form.querySelector('[type="submit"]'); submitBtn.disabled = true; submitBtn.textContent = 'Отправляем...'; try { const response = await fetch(this.form.dataset.action, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ ...this.formData, sessid: this.form.dataset.sessid, }), }); const result = await response.json(); if (result.success) { this.showSuccessScreen(); } else { this.showError(result.error || 'Ошибка отправки'); submitBtn.disabled = false; submitBtn.textContent = 'Отправить'; } } catch (e) { this.showError('Ошибка соединения. Попробуйте позже.'); submitBtn.disabled = false; } } showSuccessScreen() { this.form.innerHTML = ` <div class="form-success"> <h3>Спасибо! Мы свяжемся с вами в течение часа.</h3> </div> `; } showError(message) { let errEl = this.form.querySelector('.form-global-error'); if (!errEl) { errEl = document.createElement('div'); errEl.className = 'form-global-error'; this.steps[this.current].prepend(errEl); } errEl.textContent = message; } } document.querySelectorAll('.multistep-form').forEach(el => new MultistepForm(el)); Серверный обработчик
// /local/ajax/multistep_form.php \Bitrix\Main\Loader::includeModule('crm'); $data = json_decode(file_get_contents('php://input'), true); $sessid = $data['sessid'] ?? ''; if (!check_bitrix_sessid($sessid)) { http_response_code(403); echo json_encode(['error' => 'Forbidden']); exit; } $name = htmlspecialchars(trim($data['name'] ?? '')); $phone = htmlspecialchars(trim($data['phone'] ?? '')); $email = htmlspecialchars(trim($data['email'] ?? '')); $service = htmlspecialchars($data['service'] ?? ''); $budget = htmlspecialchars($data['budget'] ?? ''); $message = htmlspecialchars($data['message'] ?? ''); if (empty($name) || empty($phone)) { echo json_encode(['error' => 'Не заполнены обязательные поля']); exit; } $comments = implode("\n", array_filter([ $service ? "Услуга: {$service}" : '', $budget ? "Бюджет: {$budget}" : '', $message ? "Комментарий: {$message}" : '', ])); $lead = new \CCrmLead(false); $leadId = $lead->Add([ 'TITLE' => 'Заявка с сайта — ' . $name, 'NAME' => $name, 'PHONE' => [['VALUE' => $phone, 'VALUE_TYPE' => 'WORK']], 'EMAIL' => [['VALUE' => $email, 'VALUE_TYPE' => 'WORK']], 'SOURCE_ID' => 'WEB', 'COMMENTS' => $comments, ]); echo json_encode(['success' => (bool)$leadId]); Сохранение прогресса: как не потерять данные?
Для длинных форм (5+ шагов) мы добавляем сохранение в localStorage — при случайном закрытии данные восстанавливаются на том же шаге. Таймаут — 30 минут, дальше данные считаются устаревшими.
// После каждого шага localStorage.setItem('form_progress', JSON.stringify({ step: this.current, data: this.formData, savedAt: Date.now(), })); // При инициализации — восстановить, если не старше 30 минут const saved = JSON.parse(localStorage.getItem('form_progress') || 'null'); if (saved && Date.now() - saved.savedAt < 1800000) { this.formData = saved.data; this.showStep(saved.step); } Пошаговая инструкция по настройке
- Создайте новый компонент в
local/components/company/multistep.form. - Определите массив шагов с полями (как в примере выше).
- Реализуйте клиентскую логику на JavaScript с валидацией.
- Напишите серверный обработчик для создания лидов.
- Подключите компонент на страницу и настройте параметры.
Типичные ошибки при внедрении
- Отсутствие CSRF-защиты — используйте
bitrix_sessid(). - Несоответствие типов данных на клиенте и сервере.
- Игнорирование мобильной версии — проверяйте адаптивность шагов.
Этапы разработки
- Аналитика — определение необходимых полей и логики шагов.
- Проектирование — подготовка макетов и конфигурации компонента.
- Разработка — создание PHP-компонента и JS-файла.
- Тестирование — A/B тесты, проверка валидации, обработки ошибок.
- Деплой — выкатка на боевой сайт и интеграция с CRM.
Что входит в работу
- Документация по API компонента и инструкция по настройке.
- Доступ к репозиторию с исходным кодом.
- Обучение менеджеров работе с формой (заполнение, редактирование шагов).
- Гарантийная поддержка в течение 2 месяцев после деплоя.
Сроки и стоимость
| Вариант | Состав | Ориентировочный срок |
|---|---|---|
| Базовая пошаговая форма | 2–3 шага, валидация, лид в CRM | 2–4 дня |
| С кастомными полями | Выбор, радио, файл, динамические поля | 4–7 дней |
| Полный компонент | Конфигурируемые шаги, A/B, аналитика, сохранение | 8–12 дней |
Стоимость рассчитывается индивидуально — она зависит от количества шагов, сложности валидации, необходимости интеграций. Свяжитесь с нами для предварительной оценки под ваш проект. Закажите разработку пошаговой формы, чтобы повысить конверсию вашего сайта. Получите консультацию — мы проанализируем вашу форму и предложим оптимальное решение.







