Before this lesson

Complete HTML form basics. Understand name, value and the submit event.

What you will be able to do

Trace controls into submitted data and separate browser validation, business rules and network requests.

Understand the mechanism

FormData collects successful named controls. Disabled controls and unchecked checkboxes are omitted, while readonly text fields generally participate. IDs associate labels and scripts but do not replace names. Repeated names can produce multiple values, requiring getAll.

Native attributes express built-in constraints. checkValidity returns a result, while reportValidity also presents feedback. A nonempty setCustomValidity message makes a control invalid; clear it after correction or the control remains blocked.

requestSubmit follows validation and submit-event behavior similar to user activation, whereas submit bypasses those steps. Prefer requestSubmit when code should initiate normal submission. preventDefault only cancels the default action; display or network work must still be implemented.

Start with understandable fields and feedback before enhancing validation. Avoid marking untouched fields as errors immediately. Frontend rules do not enforce server authorization, uniqueness or complete business validation.

Runnable example

Run HTML examples as separate .html files in a modern browser. Prepare resource files and multi-file modules as described in the lesson.

<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Honeysuck practice</title></head><body>
<form id="signup"><label>Name <input name="name" id="name" required maxlength="30"></label>
<fieldset><legend>Topics</legend><label><input type="checkbox" name="topic" value="HTML">HTML</label><label><input type="checkbox" name="topic" value="CSS">CSS</label></fieldset>
<button>Preview data</button></form><pre id="result" role="status"></pre>
<script>
const form=document.querySelector('#signup'),nameInput=document.querySelector('#name');
function validate(){nameInput.setCustomValidity(nameInput.value.trim()?'':'Enter a name, not only spaces.');}
nameInput.addEventListener('input',validate);
form.addEventListener('submit',event=>{event.preventDefault();validate();if(!form.reportValidity())return;
 const data=new FormData(form);document.querySelector('#result').textContent=JSON.stringify({name:String(data.get('name')).trim(),topics:data.getAll('topic')},null,2);
});
</script>
</body></html>

Trace and verify

Enter a name and select both topics, then verify two values. Clear both for an empty array. Temporarily disable the name control to observe omission, restore it, and test whitespace followed by correction. This example previews data without sending it.

Common mistakes and boundaries

Clear custom errors as input changes, otherwise validation can prevent the submit event entirely. Explicitly extract fields instead of trying to serialize FormData directly as JSON; file entries are not ordinary strings.

Practice challenge

Require at least one topic, associate its feedback with the group, and preserve input. Add a requestSubmit trigger and verify equivalent behavior.

Reference solution and reasoning

Apply the group custom error to one checkbox and recompute on every topic change. Associate a stable hint ID with aria-describedby. Marking every checkbox required would require every option rather than at least one.

Further reading