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.

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.