Формы в HTML

Элемент <form> создаёт интерактивную форму для сбора данных от пользователя и отправки на сервер.

Зачем нужно

Формы -- основной способ ввода данных в вебе: авторизация, регистрация, поиск, комментарии, заказы, фильтры. Без форм веб-приложения не могут взаимодействовать с пользователем.

Где используется

  • Логин/регистрация
  • Поиск по сайту
  • Оформление заказа
  • Обратная связь, комментарии
  • Настройки профиля
  • Фильтры каталога

Предпосылки

Элемент <form>

<form action="/api/login" method="POST">
  <label for="email">Email:</label>
  <input type="email" id="email" name="email" required>

  <label for="password">Пароль:</label>
  <input type="password" id="password" name="password" required>

  <button type="submit">Войти</button>
</form>

Атрибуты <form>

Атрибут Значение Описание
action URL Куда отправлять данные
method GET / POST HTTP-метод
enctype MIME-тип Кодировка данных
novalidate boolean Отключить встроенную валидацию
autocomplete on / off Автозаполнение
name строка Имя формы
target _self, _blank Куда открыть ответ

method -- GET vs POST

<!-- GET: данные в URL (строка запроса) -->
<!-- Для поиска, фильтров, публичных данных -->
<form action="/search" method="GET">
  <input type="search" name="q">
  <button type="submit">Найти</button>
</form>
<!-- Результат: /search?q=html -->

<!-- POST: данные в теле запроса -->
<!-- Для паролей, файлов, изменения данных -->
<form action="/api/register" method="POST">
  <input type="email" name="email">
  <input type="password" name="password">
  <button type="submit">Регистрация</button>
</form>
GET POST
Данные В URL (?key=value) В теле запроса
Видимость Видны в адресной строке Скрыты
Кеширование Можно закешировать Нельзя
Закладки Можно сохранить Нельзя
Длина Ограничена (~2048 символов) Неограничена
Применение Поиск, фильтры Логин, файлы, мутации

enctype -- кодировка данных

<!-- По умолчанию: key=value&key2=value2 -->
<form method="POST" enctype="application/x-www-form-urlencoded">

<!-- Для загрузки файлов (обязательно!) -->
<form method="POST" enctype="multipart/form-data">
  <input type="file" name="avatar">
  <button type="submit">Загрузить</button>
</form>

<!-- Чистый текст (редко используется) -->
<form method="POST" enctype="text/plain">

Процесс отправки формы

1. Пользователь нажимает submit
2. Браузер валидирует поля (required, pattern, type)
3. Если валидация провалена -- показ ошибок, отправка не происходит
4. Если ОК -- данные кодируются согласно enctype
5. GET: данные добавляются в URL как query string
   POST: данные отправляются в теле HTTP-запроса
6. Браузер переходит на URL из action (или перезагружает страницу)

Отправка через JavaScript (без перезагрузки)

<form id="contactForm">
  <input type="text" name="name" required>
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <button type="submit">Отправить</button>
</form>

<script>
  document.getElementById('contactForm').addEventListener('submit', async (e) => {
    e.preventDefault(); // Предотвращает стандартную отправку

    const formData = new FormData(e.target);

    try {
      const response = await fetch('/api/contact', {
        method: 'POST',
        body: formData
      });

      if (response.ok) {
        alert('Сообщение отправлено!');
        e.target.reset();
      }
    } catch (error) {
      console.error('Ошибка:', error);
    }
  });
</script>

Объект FormData

const form = document.querySelector('form');
const formData = new FormData(form);

// Получить значение
formData.get('email');

// Добавить поле
formData.append('timestamp', Date.now());

// Перебрать все поля
for (const [key, value] of formData) {
  console.log(key, value);
}

// Отправить как JSON
const data = Object.fromEntries(formData);
fetch('/api', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(data)
});

Структура доступной формы

<form action="/api/register" method="POST">
  <fieldset>
    <legend>Личные данные</legend>

    <div class="field">
      <label for="name">Имя:</label>
      <input type="text" id="name" name="name" required autocomplete="given-name">
    </div>

    <div class="field">
      <label for="email">Email:</label>
      <input type="email" id="email" name="email" required autocomplete="email">
    </div>
  </fieldset>

  <fieldset>
    <legend>Безопасность</legend>

    <div class="field">
      <label for="password">Пароль:</label>
      <input type="password" id="password" name="password"
             required minlength="8" autocomplete="new-password">
      <p class="hint" id="password-hint">Минимум 8 символов</p>
    </div>
  </fieldset>

  <button type="submit">Зарегистрироваться</button>
</form>

Формы без <form>

Элементы формы могут существовать вне <form>, если связаны через атрибут form:

<form id="searchForm" action="/search" method="GET">
  <input type="search" name="q">
</form>

<!-- Кнопка вне формы, но привязана к ней -->
<button type="submit" form="searchForm">Найти</button>

Частые ошибки

Ошибка Почему плохо Как правильно
Нет name на input Данные не отправляются name обязателен для отправки
GET для паролей Пароль виден в URL method="POST" для паролей
Нет enctype при загрузке файлов Файл не отправится enctype="multipart/form-data"
Вложенные формы Невалидно, непредсказуемое поведение Формы не вкладываются друг в друга
Нет label Недоступно для screen readers Каждый input должен иметь label
<a> вместо <button type="submit"> Нет стандартной отправки формы Используй <button>

Практика

  1. Создай форму логина с method="POST", email и password полями
  2. Создай поисковую форму с method="GET" -- посмотри query string в URL
  3. Создай форму загрузки файла с enctype="multipart/form-data"
  4. Перехвати отправку формы через e.preventDefault() и отправь через fetch
  5. Проверь форму через Tab -- все поля должны быть доступны с клавиатуры

Связанные темы

Ресурсы