Содержание
Как создать динамические формы с использованием JavaScript и HTML
Черновик готовит редакция с помощью ИИ. За стандарт издания отвечает главный редактор — Валерий Курземнек.
Динамическая форма — это форма, в которой JavaScript добавляет, меняет или убирает поля уже после загрузки страницы: например, кнопка «Добавить телефон» создаёт ещё одно поле ввода. Для такой формы нужны три инструмента: разметка `<form>` в HTML, метод `createElement` или элемент `<template>` для новых полей и объект `FormData` с `fetch` для отправки данных без перезагрузки. Ниже — каждый шаг с примерами кода, сверенными с документацией MDN в 2026 году.
Пять опорных точек:
- Каркас формы задаёт HTML: `<form>`, `<input>`, `<label>`. JS только управляет этим каркасом.
- Новые поля создаются через `document.createElement`, `insertAdjacentHTML` или клонирование `<template>`.
- Каждому динамическому полю нужен атрибут `name` — без него значение поля не попадёт в отправляемые данные.
- Валидацию до отправки берёт на себя Constraint Validation API: `checkValidity`, `reportValidity`, `setCustomValidity`.
- Отправка без перезагрузки — `new FormData(form)` плюс `fetch`.
Основы HTML и CSS для форм
До JavaScript нужен статичный каркас — базовые элементы HTML и немного CSS.
HTML-форма
HTML-форма создаётся тегом `<form>`. Это контейнер для всех полей; атрибут `action` задаёт адрес, куда уйдут данные после отправки.
| «`html
<form action=»/submit» method=»post»> <!— Элементы будут здесь —> </form> «` |
HTML-поля ввода
Данные принимают поля ввода: текст, радиокнопки, флажки, списки. Текстовое поле создаётся тегом `<input>` с `type=»text»`, а `<label>` связывает подпись с полем.
| «`html
<label for=»username»>Имя пользователя:</label> <input type=»text» id=»username» name=»username»> «` |
CSS-стилизация
Внешний вид полей настраивается через CSS: ширина, отступы, рамки, скругления.
| «`css
input[type=»text»] { width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 5px; } «` |
Каркас готов — дальше динамические поля.
Добавление динамических элементов с помощью JavaScript
JavaScript — ключевой язык для создания динамических элементов на веб-страницах: поля формы добавляются, удаляются и меняются во время работы пользователя, без обновления страницы.
Основы JavaScript
Три опоры любой динамической формы:
- Выбор элементов: метод `querySelector` находит элемент на странице по CSS-селектору.
| «`javascript
const inputField = document.querySelector(‘#username’); «` |
- Создание элементов: метод `document.createElement` создаёт новый элемент, а `appendChild` вставляет его на страницу.
| «`javascript
const newInput = document.createElement(‘input’); newInput.type = ‘text’; newInput.name = ‘phone’; document.body.appendChild(newInput); «` |
- Обработка событий: `addEventListener` вешает обработчик, который реагирует на действия пользователя — клики, ввод, отправку формы.
| «`javascript
inputField.addEventListener(‘change’, function(event) { console.log(`Новое значение: ${event.target.value}`); }); «` |
Добавление полей ввода динамически
Классическая задача: кнопка добавляет новое текстовое поле при каждом нажатии.
| «`html
<form action=»/submit» method=»post» id=»myForm»> <div id=»inputContainer»> <!— Сюда будут добавляться поля ввода —> </div> <button type=»button» id=»addInput»>Добавить поле ввода</button> <button type=»submit»>Отправить</button> </form> <script src=»script.js»></script> «` |
Код script.js, который добавляет поле по клику:
| «`javascript
document.addEventListener(‘DOMContentLoaded’, function() { const inputContainer = document.getElementById(‘inputContainer’); const addButton = document.getElementById(‘addInput’); let counter = 0; addButton.addEventListener(‘click’, function() { const newInput = document.createElement(‘input’); newInput.type = ‘text’; newInput.name = `extra_${counter++}`; inputContainer.appendChild(newInput); }); }); «` |
Ключевая строка — `newInput.name = …`. По документации MDN, в отправку попадают только «успешные» поля: с атрибутом `name` и без `disabled`. Поле без `name` заполнить можно, но на сервер значение не уйдёт — самая частая ошибка в динамических формах. Шаблонный код руками писать необязательно: AI-ассистенты вроде Claude Code генерируют заготовку формы по описанию.
Удаление полей и делегирование событий
Рядом с каждым добавленным полем нужна кнопка удаления. Вешать обработчик на каждую кнопку неудобно — один обработчик ставится на контейнер, а внутри проверяется, по чему кликнули. Приём называется делегированием событий:
| «`javascript
inputContainer.addEventListener(‘click’, function(event) { if (event.target.matches(‘.remove-btn’)) { event.target.closest(‘.form-row’).remove(); } }); «` |
Обработчик один, а работает для всех строк — и для тех, что появятся позже: обработчики, навешанные при загрузке, о новых полях не знают, делегирование эту проблему снимает.
Шаблон template для повторяющихся блоков

Когда динамический блок состоит из нескольких элементов — подпись, поле, кнопка удаления, — собирать его через `createElement` по кусочку громоздко. Для этого в HTML есть элемент `<template>`: по документации MDN, это механизм для хранения фрагментов HTML, которые по умолчанию не отображаются на странице, а используются позже через JavaScript.
| «`html
<template id=»rowTemplate»> <div class=»form-row»> <input type=»text» name=»items[]»> <button type=»button» class=»remove-btn»>Удалить</button> </div> </template> «` |
| «`javascript
const template = document.getElementById(‘rowTemplate’); addButton.addEventListener(‘click’, function() { const row = document.importNode(template.content, true); inputContainer.appendChild(row); }); «` |
Содержимое шаблона лежит в свойстве `content`, копию создаёт `document.importNode` — MDN рекомендует его, чтобы вложенные кастомные элементы создавались в контексте текущего документа. Разметка блока остаётся в HTML, а JavaScript сводится к трём строкам.
Валидация формы на JavaScript до отправки
Перед отправкой форму нужно проверить. Большую часть работы браузер делает сам — через атрибуты валидации: `required` требует заполнить поле, `minlength` и `maxlength` ограничивают длину текста, `min`, `max` и `step` — числовые значения, `type` проверяет формат (например, email), а `pattern` сверяет ввод с регулярным выражением.
Динамическим формам этого мало: поля появляются на лету, проверять их нужно из кода — для этого есть Constraint Validation API, описанный в документации MDN:
- `checkValidity()` — возвращает `true`, если у значения нет проблем с валидностью, иначе `false` и событие `invalid` на элементе;
- `reportValidity()` — то же самое, но браузер ещё и показывает пользователю сообщения об ошибках;
- `setCustomValidity(message)` — задаёт собственный текст ошибки; пока он задан, элемент считается невалидным;
- `validationMessage` — готовый локализованный текст ошибки для текущего поля.
Подсветить проблемные поля можно чистым CSS: псевдоклассы `:valid` и `:invalid` срабатывают сразу, а `:user-valid` и `:user-invalid` — только после взаимодействия пользователя с полем, поэтому форма не «краснеет» при первой загрузке.
С валидацией связано различие двух методов отправки. По MDN, `form.submit()` просто отправляет форму — без проверки и события `submit`. `form.requestSubmit()` ведёт себя как клик по кнопке отправки: форма валидируется, отправка идёт только при успешной проверке, событие `submit` срабатывает. В коде динамических форм почти всегда нужен второй.
Одно предупреждение, дословно повторяющееся в документации: клиентская валидация — не мера безопасности. Проверку на стороне сервера она не заменяет, потому что запрос к серверу можно сформировать и в обход формы.
Обработка данных из формы
Заполненную форму нужно собрать и отправить. Обычная HTML-отправка перезагружает страницу: по описанию MDN, браузер переходит на URL из атрибута `action` с полной загрузкой. Одностраничные приложения используют форму только для сбора ввода, отправкой занимается JavaScript.
Сбор данных: объект FormData
Интерфейс `FormData` собирает пары «ключ — значение» из полей формы. Если передать в конструктор саму форму, объект заполнится автоматически: ключами станут атрибуты `name` полей, значениями — введённые данные, включая содержимое файловых полей.
| «`javascript
const form = document.getElementById(‘myForm’); const formData = new FormData(form); for (const [key, value] of formData) { console.log(key, value); } «` |
Перебор `for…of` отдаёт все пары, в том числе несколько значений с одинаковым ключом — так собираются данные из повторяющихся полей `name=»items[]»`. Отдельные значения добавляются и читаются методами `append`, `get`, `set` и `delete`.

- Возможность получить Доступ в Нейроклуб на целый месяц
- Как ИИ ускоряет работу и приносит деньги
- За 2 часа вы получите четкий план, как начать работать с ИИ прямо сейчас!
Отправка данных на сервер

Отправляет данные `fetch`: объект `FormData` передаётся в тело запроса. Заголовок Content-Type указывать не нужно — по документации MDN, при передаче `FormData` в `fetch` корректный заголовок ставится автоматически, в формате `multipart/form-data`.
| «`javascript
form.addEventListener(‘submit’, async function(event) { event.preventDefault(); try { const response = await fetch(‘/submit’, { method: ‘POST’, body: new FormData(form) }); console.log(await response.json()); } catch (error) { console.error(‘Ошибка отправки:’, error); } }); «` |
`event.preventDefault()` отменяет стандартную отправку, данные уходят фоновым запросом, ответ обрабатывается на той же странице. Дальше данные из форм обычно попадают в CRM и отчёты — их обработку можно автоматизировать с помощью AI.
Использование библиотеки jQuery
В старых проектах динамические формы часто собраны на jQuery: `$(‘#inputContainer’).append(…)` вместо `createElement`, `$.ajax` вместо `fetch`. Такой код работает, трогать его без причины не стоит. Для новых форм библиотека не требуется: те же задачи закрывают встроенные `querySelector`, `addEventListener`, `FormData` и `fetch`.
Сравнение способов создания полей формы
Три способа добавить поле из JS решают задачу по-разному:
| Способ | Когда подходит | Ограничения |
| `document.createElement` | Одно-два простых поля, полный контроль над атрибутами из кода | Многословный: каждый атрибут и вложенный элемент — отдельная строка |
| `insertAdjacentHTML` | Готовая строка разметки, вставляемая в нужную точку | Разметка живёт строкой в JS-коде; вставлять в неё пользовательский ввод небезопасно |
| `<template>` + `importNode` | Повторяющиеся блоки из нескольких элементов: строка «поле + кнопка удаления» | Требует заранее описать блок в HTML-разметке страницы |
Правило: одиночному полю хватает `createElement`, повторяющимся блокам — `<template>`.
Заключение
Динамическая форма собирается из четырёх слоёв: HTML-каркас, добавление и удаление полей через `createElement` или `<template>`, проверка через Constraint Validation API и отправка через `FormData` с `fetch`. Всё это встроенные возможности браузера.
Типовые ошибки, которые ломают динамические формы: созданное поле без атрибута `name` (значение не уйдёт на сервер), обработчики на самих полях вместо делегирования (новые поля остаются «глухими») и отправка через `submit()` вместо `requestSubmit()` (валидация молча пропускается).
Формы — частая задача для программной генерации: каркас с полями по описанию строят через Claude Code API, а валидацию и отправку оставляют коду из этой статьи.
Частые вопросы о формах на JavaScript
Чем requestSubmit() отличается от submit()?
`submit()` отправляет форму без проверки и без события `submit`. `requestSubmit()` ведёт себя как клик по кнопке отправки: сначала валидация, отправка только при успешной проверке, событие `submit` срабатывает.
Почему динамическое поле не попадает в отправку данных?
В данные формы попадают только поля с атрибутом `name`, не отключённые атрибутом `disabled`. Полю, созданному из JavaScript, атрибут `name` нужно задать явно.
Нужно ли указывать заголовок Content-Type при отправке FormData через fetch?
Не нужно: при передаче объекта `FormData` в `fetch` корректный заголовок устанавливается автоматически — данные уходят в формате `multipart/form-data`.
Достаточно ли проверки формы на стороне браузера?
Недостаточно. Клиентская валидация улучшает интерфейс, но её легко обойти, поэтому проверка данных на сервере обязательна в любом случае.
- Выполним базовые задачи на российских нейросетях и посмотрим на результаты!
- Файл-инструкцию «Как сделать нейро-фотосессию из своего фото бесплатно, без иностранных карт и прочих сложностей»
- Покажем 10+ способов улучшить свою жизнь с ИИ каждому — от ребенка и пенсионера до управленца и предпринимателя
- Возможность получить Доступ в Нейроклуб на целый месяц
- Как ИИ ускоряет работу и приносит деньги
- За 2 часа вы получите четкий план, как начать работать с ИИ прямо сейчас!
