Ответ
Обязательно добавляй <form> для семантики и обработки событий submit. Используй <button type="submit"> для отправки. Для валидации и доступности:
<form>
<div>
<label for="email">Email</label>
<input type="email" id="email" required>
<span class="error" aria-live="polite"></span>
</div>
<fieldset>
<legend>Выберите вариант</legend>
<input type="radio" id="opt1" name="options">
<label for="opt1">Вариант 1</label>
</fieldset>
<button type="submit">Отправить</button>
</form>
Ключевые элементы:
fieldsetиlegendдля группировкиrequiredдля обязательных полей- Валидационные сообщения
aria-*атрибуты для доступности- CSRF-токен для безопасности (если нужно)
Ответ 18+ 🔞
Слушай, а вот этот твой <form> — это ж, блядь, как та самая тётка на рынке, которая всё в одну авоську собирает, а потом орёт, что чего-то не хватает. Так и тут: если не обернуть всё как надо, получится пиздец, а не форма.
Вот смотри, в чём прикол. Ты ж не просто кучу <input> на страну кидаешь? Ты их в структуру, в логику собираешь. <form> — это и есть та самая авоська, которая говорит браузеру: «Эй, чувак, вот эти все поля — они вместе, и их надо куда-то отправить одним махом». Без неё кнопка «Отправить» будет просто куском красивой, но бесполезной хуйни.
А <button type="submit"> — это уже прямой пинок под жопу этой самой авоське. «Ну чё, поехали, нефиг тут выёбываться!». Не type="button", а именно submit, иначе никуда она не поедет, будет тупить на месте.
Теперь про валидацию и доступность — это, сука, как инструкция к микроволновке. Кажется, да похуй, засунул — греется. А потом оказывается, что контейнер не для СВЧ, всё расплавилось, и ты сидишь с ебалом, обосанным от горя. Так и тут.
requiredна инпуте — это как надпись «Не суй сюда металлические вилки, долбоёб». Браузер сразу орёт, если поле пустое.<fieldset>с<legend>— это как раздел в холодильнике: «Молочка», «Овощи». Не смешивай всё в одну кучу, а то потом ищешь сыр, а он между пивом и селёдкой завалялся. Группируй связанные радио-кнопки, чтобы и скринридер, и пользователь не ебали мозг.aria-live="polite"на спане для ошибок — это шепоток на ушко скринридеру: «Слышь, братан, тут пользователь косякнул, сообщение вылезло, прочитай ему, но не перебивай». Без этого слепой юзер просто не узнает, в чём его косяк.- А
forу лейбла, привязанный кidинпута — это вообще основа основ. Это как связать носки резиночкой, чтобы не растерять. Кликнул по тексту «Email» — курсор уже мигает в поле ввода. Магия, блядь! А без этого — кликаешь, хуй тебе, а не фокус.
И да, про безопасность. CSRF-токен — это как штампик в паспорт на входе в клуб. Без него тебя не пустят, потому что думают, что ты левый мудак, который хочет отправить данные от чужого имени. Просто вставь скрытое поле в форму, и все будут спокойны.
Вот, смотри, как это выглядит вживую, по твоему же примеру:
<form action="/submit-your-data" method="POST">
<!-- Токен, чтоб всякие пидарасы не налетели -->
<input type="hidden" name="_csrf" value="тут_длинная_хуйня_из_символов">
<div>
<label for="email">Твой email, будь человеком</label>
<input type="email" id="email" name="email" required aria-describedby="email-error">
<!-- Место для сообщения об ошибке, которое появится, если накосячишь -->
<span id="email-error" class="error" aria-live="polite"></span>
</div>
<!-- Группировка, ёпта! Чтоб понятно было, что выбираешь ОДИН из вариантов -->
<fieldset>
<legend>Выбери один вариант, не будь тварью</legend>
<input type="radio" id="opt1" name="options" value="1">
<label for="opt1">Вариант первый (обычно самый скучный)</label>
<br>
<input type="radio" id="opt2" name="options" value="2">
<label for="opt2">Вариант второй (тут уже веселее)</label>
</fieldset>
<!-- КНОПКА-ПИНОК. Без type="submit" форма будет просто молча смотреть на тебя, как баран на новые ворота -->
<button type="submit">Отправить всё это дело</button>
</form>
Вот и вся философия. Сделал по этим правилам — и форма будет не просто куском верстки, а рабочим, доступным и безопасным механизмом. А не сделаешь — получишь мартышку с гранатой, которая в любой момент может ебнуть пользователю прямо в лицо.