Developing Multistep Feedback Forms for 1C-Bitrix
Situations Where a Multistep Form Is Indispensable
We've encountered this scenario multiple times: a client requests a "feedback form," but after release it turns out they need to collect context — the type of issue, order number, attached screenshots. A regular form falls short: either all fields are visible at once, or the user gets confused. A multistep form with conditional logic is the only way to get structured submissions without overwhelming the user. For example, in one project for an online store, we implemented a form with 5 inquiry types, each with its own set of fields. After deployment, incomplete submissions dropped by 40%.
What Sets It Apart from a Step-by-Step Funnel Form?
The goal is not a sale, but collecting technical information. The inquiry type determines subsequent steps. It's not just a form — it's a mini Service Desk.
Conditional Logic in Practice
The user selects an inquiry type on the first step: "Technical Question," "Payment Issue," "Complaint," or "Other." After selection, relevant fields are dynamically loaded. For instance, selecting "Technical Question" shows fields for "Product," "Error Description," and a screenshot upload. Selecting "Payment Issue" shows fields for "Order Number," "Amount," and issue type. The step configuration is defined in JSON — allowing logic changes without rewriting code:
{
"steps": [
{
"id": "type",
"fields": [{"name": "type", "type": "select", "options": [...]}]
},
{
"id": "technical",
"showWhen": {"field": "type", "value": "technical"},
"fields": [{"name": "product", "type": "text"}, {"name": "error", "type": "textarea"}]
}
]
}
The implementation uses plain JavaScript — no external libraries. Below is the ConditionalMultistepForm controller, which calculates the step path based on answers.
class ConditionalMultistepForm {
constructor(config) {
this.config = config;
this.answers = {};
this.stepsPath = this.calculatePath();
this.currentIndex = 0;
}
calculatePath() {
return this.config.steps.filter(step => {
if (!step.showWhen) return true;
const {field, value} = step.showWhen;
const answer = this.answers[field];
return Array.isArray(value) ? value.includes(answer) : answer === value;
});
}
handleAnswer(fieldName, value) {
this.answers[fieldName] = value;
this.stepsPath = this.calculatePath();
}
get currentStep() {
return this.stepsPath[this.currentIndex] ?? null;
}
get totalSteps() {
return this.stepsPath.length;
}
canGoNext() {
const step = this.currentStep;
if (!step) return false;
return step.fields
.filter(f => f.required)
.every(f => !!this.answers[f.name]);
}
next() {
if (!this.canGoNext()) return false;
if (this.currentIndex < this.stepsPath.length - 1) {
this.currentIndex++;
return true;
}
return false;
}
prev() {
if (this.currentIndex > 0) {
this.currentIndex--;
}
}
isLastStep() {
return this.currentIndex === this.stepsPath.length - 1;
}
getSubmitData() {
return {
type: this.answers.type,
answers: this.answers,
};
}
}
Step configuration is defined in JSON — allowing logic changes without rewriting code.
Why Entrust Development to Our Engineers?
We bring over 10 years of experience developing on Bitrix and Bitrix24. We've implemented dozens of multistep forms for online stores, technical support, and corporate portals. Each form is not just code, but a well-thought-out architecture: backup, tagged caching, error handling. We guarantee the form performs under high loads. For instance, for a client with a catalog of 50,000 products, the form processes up to 200 submissions per day without slowdown. Our conditional multistep form reduces abandonment rates by 3x compared to traditional single-page forms, and clients typically save 30% on support costs after implementation, translating to $500–$2,000 monthly savings depending on volume.
What's Included in the Work?
| Stage | Content | Result |
|---|---|---|
| Analysis | Interview with you, study of inquiry types | Technical specification with step descriptions and conditions |
| Design | JSON config, interface prototype | UX mockup and data architecture |
| Development | Backend: PHP handlers, CRM integration; Frontend: JS controller, markup | Working form with conditional logic |
| Integration | Connection to 1C (if needed), notification setup | Form writes data to CRM or email |
| Testing | Check all scenarios, including edge cases | Testing report |
| Documentation | Instructions for customizing fields and conditions | PDF document |
How Are Files Handled?
The user can attach a screenshot. We implemented immediate upload to the server upon file selection — more convenient than uploading at the end. The file is saved using CFile::SaveFile, returning a file_id that is passed on final submission.
// /local/ajax/upload_temp_file.php
if (!$_FILES['file'] || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
echo json_encode(['error' => 'Upload error']);
exit;
}
$allowedMime = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($_FILES['file']['type'], $allowedMime)) {
echo json_encode(['error' => 'Invalid file type']);
exit;
}
$fileId = \CFile::SaveFile([
'name' => $_FILES['file']['name'],
'size' => $_FILES['file']['size'],
'tmp_name' => $_FILES['file']['tmp_name'],
'type' => $_FILES['file']['type'],
], 'feedback_forms');
echo json_encode(['file_id' => $fileId]);
How Does Data Get into CRM?
Depending on the inquiry type, a deal or lead is created in Bitrix24. We use REST API for reliable integration.
- Technical question → deal in the 'Support' pipeline
- Payment issue → lead linked to order
- Complaint → lead with a tag
switch ($type) {
case 'technical':
$deal = new \CCrmDeal(false);
$deal->Add([
'TITLE' => 'Tech inquiry: ' . $data['answers']['product'] ?? '',
'CATEGORY_ID' => CRM_SUPPORT_PIPELINE_ID,
'STAGE_ID' => 'C' . CRM_SUPPORT_PIPELINE_ID . ':NEW',
'COMMENTS' => $data['answers']['error_text'] ?? '',
'CONTACT_ID' => $this->findOrCreateContact($data),
]);
break;
// ... other types
}
How to Set Up Notifications?
When an inquiry is created, the responsible manager receives an email via the FEEDBACK_NEW_TICKET mail event. The email template is configured in the Bitrix admin panel.
\Bitrix\Main\Mail\Event::send([
'EVENT_NAME' => 'FEEDBACK_NEW_TICKET',
'LID' => SITE_ID,
'C_FIELDS' => [
'TYPE' => $typeLabel,
'NAME' => $data['answers']['name'],
'EMAIL' => $data['answers']['email'],
'TEXT' => json_encode($data['answers'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT),
],
'TO_EMAIL' => FEEDBACK_MANAGER_EMAIL,
]);
Comparison: Conditional Form vs. Regular Form
| Parameter | Regular Form | Multistep with Conditions |
|---|---|---|
| Number of fields on screen | All at once | Only relevant ones |
| Risk of abandonment | High (long form) | Low (step by step) |
| Data quality | Low (required fields skipped) | High (context collected) |
| Development time | 1–2 days | 3–10 days |
Development Timelines
| Option | Scope | Timeframe |
|---|---|---|
| Basic multistep | 2–3 steps, inquiry type, lead in CRM | 3–5 days |
| With conditional logic | Different fields per type, file upload | 6–10 days |
| Full Service Desk | + Personal account, inquiry statuses, SLA | 15–25 days |
Quick Steps to Complete Your Form
- Select an inquiry type from the dropdown.
- Fill in the fields that appear based on your selection.
- Attach any relevant files (screenshots, documents).
- Review your information and submit.
The entire process takes less than 2 minutes on average — 60% faster than traditional forms.
Example JSON step configuration
{
"steps": [
{
"id": "type",
"fields": [
{
"name": "type",
"type": "select",
"options": [
{"value": "technical", "label": "Technical question"},
{"value": "payment", "label": "Payment issue"},
{"value": "complaint", "label": "Complaint"}
]
}
]
},
{
"id": "technical",
"showWhen": {"field": "type", "value": "technical"},
"fields": [
{"name": "product", "type": "text", "label": "Product", "required": true},
{"name": "error", "type": "textarea", "label": "Error description", "required": true},
{"name": "screenshot", "type": "file", "label": "Screenshot"}
]
},
{
"id": "payment",
"showWhen": {"field": "type", "value": "payment"},
"fields": [
{"name": "order_id", "type": "text", "label": "Order number", "required": true},
{"name": "amount", "type": "number", "label": "Amount", "required": true},
{"name": "issue", "type": "select", "label": "Issue type", "options": [
{"value": "refund", "label": "Refund"},
{"value": "delay", "label": "Delay"}
]}
]
}
]
}
If you have any questions, contact us — we will evaluate your project free of charge and offer the best solution. Get a consultation: write to us, and we'll show you how it works on your project.







