HTML Forms Can Do More Than You Think
Forms are one of the places where JavaScript gets added very quickly.
A developer needs email validation, so a library appears. A field needs a minimum value, so a custom script is added. Mobile users need a better keyboard, so another workaround is built.
Modern HTML already handles many of these cases.
That does not mean you never need JavaScript in a form. Complex forms still need custom logic. But it is worth learning what the browser can do before rebuilding it yourself.
Use the correct input type
This works:
<input type="text">
But it tells the browser almost nothing.
For email:
<input type="email">
For URLs:
<input type="url">
For phone numbers:
<input type="tel">
For search:
<input type="search">
For numbers:
<input type="number">
The correct type can improve validation, mobile keyboards, and browser behaviour.
Required fields
<input
type="email"
name="email"
required
>
The browser can stop the form from being submitted when the field is empty.
Minimum and maximum values
For numbers:
<input
type="number"
min="1"
max="10"
>
For dates:
<input
type="date"
min="2026-01-01"
max="2026-12-31"
>
For text length:
<input
type="text"
minlength="3"
maxlength="50"
>
These basic rules do not need a validation library.
Step values
<input
type="number"
min="0"
step="0.5"
>
Or:
<input
type="number"
min="0"
step="0.01"
>
Pattern matching
For some text fields, you can use pattern:
<input
type="text"
pattern="[A-Z]{2}[0-9]{4}"
>
That example expects two capital letters followed by four digits.
Do not turn pattern into a huge unreadable regular expression if a simpler form design would work better.
Useful autocomplete
The autocomplete attribute helps browsers fill forms correctly.
<input
name="name"
autocomplete="name"
>
<input
type="email"
name="email"
autocomplete="email"
>
<input
name="street"
autocomplete="street-address"
>
<input
name="postal"
autocomplete="postal-code"
>
This can make checkout and contact forms much faster to complete.
One-time codes
<input
type="text"
inputmode="numeric"
autocomplete="one-time-code"
>
On supported phones, the operating system may offer a received verification code automatically.
Better mobile keyboards
Use inputmode when the expected keyboard is different from the data type.
<input
type="text"
inputmode="numeric"
>
This is useful for codes made only from digits.
Remember that inputmode does not validate the value. It only helps the browser choose a keyboard.
Labels matter
Always connect a visible label to its field.
<label for="email">
Email address
</label>
<input
id="email"
name="email"
type="email"
>
Or wrap the field:
<label>
Email address
<input name="email" type="email">
</label>
Do not use placeholder text as the only label.
Help text
If a field needs more explanation:
<label for="password">
Password
</label>
<input
id="password"
type="password"
aria-describedby="password-help"
>
<p id="password-help">
Use at least 12 characters.
</p>
Now assistive technology can connect the help text to the field.
Native validation states
CSS can style validation states.
input:user-invalid {
border-color: red;
}
input:user-valid {
border-color: green;
}
I prefer :user-invalid over :invalid in many forms because it avoids showing an error before the user has interacted with the field.
Do not rely only on color
A red border alone is not a complete error message.
Users should also get clear text explaining what went wrong.
For more complex validation, JavaScript can still be useful for better messages.
Group related controls
Use <fieldset> and <legend> for related radio buttons or checkboxes.
<fieldset>
<legend>Preferred contact method</legend>
<label>
<input type="radio" name="contact" value="email">
Email
</label>
<label>
<input type="radio" name="contact" value="phone">
Phone
</label>
</fieldset>
This gives the group a clear name.
A simple contact form
<form action="/contact" method="post">
<label for="name">
Name
</label>
<input
id="name"
name="name"
autocomplete="name"
required
>
<label for="email">
Email
</label>
<input
id="email"
name="email"
type="email"
autocomplete="email"
required
>
<label for="message">
Message
</label>
<textarea
id="message"
name="message"
minlength="10"
required
></textarea>
<button type="submit">
Send message
</button>
</form>
This already has useful labels, autocomplete, email validation, required fields, and a minimum message length.
No JavaScript is needed for those basics.
Server-side validation still matters
Browser validation helps the user, but never trust it as your only validation.
A user can bypass client-side checks.
Your server should still validate required values, formats, limits, permissions, and anything that affects security or stored data.
Start with HTML
My preferred order is:
HTML input type
↓
HTML validation attributes
↓
autocomplete / inputmode
↓
clear labels and help text
↓
CSS states
↓
JavaScript only for rules HTML cannot handle
That usually leads to a smaller and more reliable form.
HTML forms are not perfect, but they can do much more than many websites let them.