Part 4: Forms and User Input
Introduction
Forms are the primary way users send data to a server. Every login page, search box, settings panel, and data entry screen is built on HTML form elements. Getting forms right — semantically correct labels, proper input types, built-in validation — reduces the amount of JavaScript needed and makes pages more accessible by default.
This part covers every form element I use regularly, along with the patterns that make forms work correctly without relying entirely on custom JavaScript.
The <form> Element
<form> Element<form action="/submit" method="post">
<!-- form fields -->
<button type="submit">Submit</button>
</form>Key attributes:
action
URL
Where to send the form data. Defaults to current URL if omitted.
method
get, post
HTTP method. get appends data to URL; post sends in body.
enctype
application/x-www-form-urlencoded, multipart/form-data, text/plain
How to encode form data. Required multipart/form-data for file uploads.
novalidate
boolean
Disables browser's built-in validation (useful when handling validation in JavaScript).
autocomplete
on, off
Whether to allow browser autocomplete.
GET vs POST:
GET— data goes in the URL query string. Use for search forms, filtering, anything that should be bookmarkable.POST— data goes in the request body, not visible in the URL. Use for logins, data submissions, anything that modifies server state.
Labels
Labels are the most important accessibility element in a form. Every interactive form field needs a label.
Explicit Label
The for attribute matches the id of the input. Clicking the label focuses the input — this is especially important on mobile where tap targets are small.
Implicit Label (Wrapped)
When the input is inside the <label>, the for/id linkage is implicit. Both styles are valid.
Never use placeholder text as a substitute for a label. Placeholders disappear when typing starts and do not work as accessible labels. They are appropriate as examples of expected format, not as the field's purpose.
The <input> Element
<input> Element<input> is the most versatile form element. The type attribute controls what kind of input it renders.
Text Inputs
Using the correct type does several things without any JavaScript:
Triggers the right keyboard on mobile (numeric for
tel,@key foremail)Enables browser-native format validation
Enables browser autocomplete for the correct category of data
Number Inputs
Date and Time Inputs
Date inputs render a date picker natively in most browsers, removing the need for a JavaScript date picker library for basic use.
Checkbox
For multiple independent options:
checked pre-checks the box.
Radio Buttons
Radio buttons form a group where only one can be selected. Group them with the same name:
File Input
For multiple files:
The form must use enctype="multipart/form-data" for file uploads to work.
Hidden Input
Hidden inputs submit data with the form without being visible to the user. Commonly used for CSRF tokens, pre-filled values, or state management.
Range Slider
Color Picker
<textarea>
<textarea>Multi-line text input:
rows and cols set the default visible size. resize: none in CSS if you want to prevent user resizing.
<select> and <option>
<select> and <option>Dropdown menu:
Pre-select an option with selected:
Option Groups
Multiple Select
<fieldset> and <legend>
<fieldset> and <legend>Group related inputs visually and semantically:
Screen readers announce the <legend> text as context for the fields within the <fieldset>.
Buttons
Always specify type. Without it, the default is submit, which means buttons inside a form will submit it unless explicitly typed otherwise. This catches many developers by surprise.
Built-in Validation Attributes
HTML provides validation attributes that work without JavaScript:
required
Field must have a value
minlength="n"
Minimum character count
maxlength="n"
Maximum character count
min="n"
Minimum value (number/date inputs)
max="n"
Maximum value (number/date inputs)
pattern="regex"
Value must match regular expression
type="email"
Browser validates email format
type="url"
Browser validates URL format
Use the :valid and :invalid CSS pseudo-classes to style fields based on validation state:
Accessibility Best Practices for Forms
Every input has a visible label — do not rely on placeholder text alone
Group related fields with
<fieldset>and<legend>Provide error messages — don't just highlight in red, say what's wrong in text
Associate error messages with inputs using
aria-describedby:
Use
autocompleteattributes to help password managers and browsers fill fields correctly:
A Complete Form Example
Summary
<form action method>
Container for all form fields
<label for>
Accessible label linked to an input
`<input type="text
`<input type="checkbox
radio">`
<input type="file">
File uploads
<input type="hidden">
Hidden data (CSRF tokens etc.)
<textarea>
Multi-line text input
<select> / <option>
Dropdown menus
<fieldset> / <legend>
Grouping related fields
`<button type="submit
reset
required, pattern, min, max
Built-in validation
autocomplete
Hint for browser/password manager
aria-describedby
Link error messages to inputs
Up Next
Part 5 covers accessibility, SEO fundamentals, and HTML5 features that make pages more robust and discoverable.
Last updated