Build interactive HTML forms — inputs, labels, selects, textareas, file uploads, and HTML5 built-in validation. No JavaScript needed for basic constraints.
When GET: searches and filters — the data ends up in the URL so users can bookmark or share the result. When POST: logins, signups, any mutation or sensitive data — the payload goes in the request body and does not appear in the URL or browser history.
action — URL the form data is submitted to. Defaults to the current page URL if omitted.method — "get" appends data to the URL (bookmarkable). "post" sends data in the request body (for mutations and sensitive data).enctype — Encoding type. Must be "multipart/form-data" when the form includes file uploads.autocomplete — "on" (default) allows the browser to suggest saved values. "off" disables suggestions for the whole form.novalidate — Boolean. Skips HTML5 built-in validation when submitting — useful when you handle validation entirely in JavaScript.<!-- GET — data in URL query string, use for searches -->
<form action="/search" method="get">
<input type="text" name="q" placeholder="Search..." />
<button type="submit">Search</button>
</form>
<!-- POST — data in request body, use for logins & mutations -->
<form action="/login" method="post">
<input type="email" name="email" />
<input type="password" name="password" />
<button type="submit">Log in</button>
</form>Why: a paired <label> does two things — clicking it focuses the input, and screen readers read it aloud so users know what the field is for. When to hide it visually: if a label must not show, use a CSS .sr-only class instead of removing it entirely.
type — Defines the input control — "text", "email", "password", "number", "checkbox", "radio", "date", "file", and more.name — Key used when form data is submitted. Each input that should be sent needs a name.id — Unique identifier. Must match the for attribute of its <label>.value — The initial value. For checkboxes and radios, it is the value sent on submission.placeholder — Hint text shown inside the field when empty. Not a substitute for a visible label.required — Boolean. Prevents form submission if the field is empty.disabled — Boolean. Makes the field uneditable and excludes it from form submission.readonly — Boolean. Makes the field uneditable but still submits its value.autocomplete — Hints to the browser what type of data to suggest — "email", "current-password", "given-name", etc.<!-- Always pair <label for="id"> with <input id="id"> -->
<label for="email">Email</label>
<input type="email" id="email" name="email" placeholder="you@example.com" />
<label for="name">Name</label>
<input type="text" id="name" name="name" />
<label for="age">Age</label>
<input type="number" id="age" name="age" min="0" max="120" />
<!-- Checkbox -->
<input type="checkbox" id="agree" name="agree" />
<label for="agree">I agree to the terms</label>
<!-- Radio group — same name ties them together -->
<input type="radio" id="yes" name="choice" value="yes" />
<label for="yes">Yes</label>
<input type="radio" id="no" name="choice" value="no" />
<label for="no">No</label>
<!-- Select dropdown -->
<label for="country">Country</label>
<select id="country" name="country">
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
</select>
<!-- Textarea -->
<label for="bio">Bio</label>
<textarea id="bio" name="bio" rows="4"></textarea>Why enctype="multipart/form-data": without it the browser sends only the filename as text — the actual file never reaches the server. When accept: it filters the file picker to show only matching files, reducing user error. Why still validate server-side: accept is just a hint — users can bypass it.
accept — Filters the file picker. Use MIME types ("image/*", "application/pdf") or extensions (".jpg,.png"). A hint only — validate file types on the server too.multiple — Boolean. Allows the user to select more than one file at once.capture — On mobile — "user" opens the front camera, "environment" opens the rear camera instead of the file picker.<!-- Single file -->
<label for="avatar">Profile photo</label>
<input type="file" id="avatar" name="avatar" accept="image/*" />
<!-- Multiple files -->
<input type="file" name="docs" multiple accept=".pdf,.docx" />
<!-- enctype is required when uploading files -->
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit">Upload</button>
</form>Why: it stops obviously invalid data before it ever reaches the server — no JavaScript needed. When it runs: the moment the user tries to submit. Why still validate server-side: HTML validation can be bypassed with DevTools or a direct HTTP request — never rely on it alone.
required — Boolean. The field cannot be empty when the form is submitted.minlength — Minimum number of characters allowed in a text field.maxlength — Maximum number of characters allowed. The browser also prevents typing beyond this limit.min — Minimum value for number and date inputs.max — Maximum value for number and date inputs.step — Legal intervals for number and date inputs — e.g. step="0.01" for currency or step="7" for weekly dates.pattern — A regular expression the value must match. Always add a title attribute explaining the expected format.<form>
<!-- required — cannot submit if empty -->
<input type="text" name="name" required />
<!-- minlength / maxlength -->
<input type="text" name="username" minlength="3" maxlength="20" />
<!-- pattern — value must match this regex -->
<input
type="text"
name="postcode"
pattern="[A-Z]{1,2}[0-9]{1,2} [0-9][A-Z]{2}"
placeholder="SW1A 1AA"
/>
<!-- min / max for numbers and dates -->
<input type="number" name="qty" min="1" max="99" />
<input type="date" name="dob" min="1900-01-01" max="2025-12-31" />
<button type="submit">Submit</button>
</form>