Input types and built-in validation

Pick the input type that matches the data, and let the browser check it before the form is sent.

  • Beginner
  • 6 min read
  • Updated 17 Oct 2026

What you will learn

  • Pick the right input type
  • Add built-in validation constraints
  • Style invalid fields only after people interact with them

The type attribute does more than change how an input looks. It tells the browser what kind of data to expect, so it can show the right keyboard on phones, offer pickers for dates and colours, and check the value before the form is submitted.

Input types for text-like data

TypeUse forWhat the browser adds
textAny single line of textNothing special
emailOne email address, or several with multipleEmail keyboard on phones; checks the format
urlA full URL including the schemeURL keyboard; checks the format
telPhone numbersPhone keypad; no format check, because formats vary by country
searchSearch boxesOften a clear button; search key on phone keyboards
passwordPasswordsHides the characters; password managers recognise it
HTML
<label for="email">Email address</label>
<input id="email" name="email" type="email">

<label for="website">Website</label>
<input id="website" name="website" type="url" placeholder="https://example.com">

<label for="phone">Phone number</label>
<input id="phone" name="phone" type="tel">

If a browser does not recognise a type, it falls back to text, so trying a newer type is safe.

Numbers and ranges

number is for quantities you count or measure, and it accepts min, max and step:

HTML
<label for="qty">Number of loaves</label>
<input id="qty" name="qty" type="number" min="1" max="20" step="1" value="1">

range shows a slider, for values where the exact number matters less than the rough position:

HTML
<label for="crust">Crust darkness</label>
<input id="crust" name="crust" type="range" min="1" max="5" value="3">

Do not use type="number" for things that are not really numbers: phone numbers, card numbers, postcodes or account numbers. They can start with zero, be very long, or contain spaces, and number inputs may strip or reject those characters. Use type="text" with inputmode="numeric" instead, as lesson 19 explains.

Dates, times and colours

HTML
<label for="class-date">Class date</label>
<input id="class-date" name="class-date" type="date" min="2026-11-01" max="2026-12-20">

<label for="pickup">Pick-up time</label>
<input id="pickup" name="pickup" type="time" min="07:00" max="16:00" step="900">

<label for="icing">Icing colour</label>
<input id="icing" name="icing" type="color" value="#f4c2c2">

Browsers show their own pickers, which already support the keyboard and the user's locale. Whatever the display format, the submitted value is always in ISO format: 2026-11-07 for dates and 09:30 for times. step="900" on a time input means 15-minute steps, because the step is in seconds.

Other types in the same family are datetime-local, month and week. Support for month and week has historically been patchy, so check before relying on them.

Built-in validation

Add constraints with attributes, and the browser blocks submission until the values meet them:

AttributeWorks withRule
requiredMost controlsMust not be empty
minlength, maxlengthText-like types, textareaNumber of characters
min, maxnumber, range, dates and timesLowest and highest value
stepnumber, range, dates and timesAllowed increments
patternText-like typesMust match a regular expression

When someone submits an invalid form, the browser focuses the first invalid field and shows a message, such as "Please fill in this field." The message wording and appearance come from the browser and its language settings.

HTML
<!DOCTYPE html>
<html lang="en-GB">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Book a class | Riverside Bakery</title>
  <style>
    input:user-invalid { border: 2px solid #b00020; }
  </style>
</head>
<body>
  <h1>Book a class</h1>
  <form action="/book" method="post">
    <p>
      <label for="name">Full name</label>
      <input id="name" name="name" type="text" required minlength="2" maxlength="80">
    </p>
    <p>
      <label for="email">Email address</label>
      <input id="email" name="email" type="email" required>
    </p>
    <p>
      <label for="places">Places (1 to 4)</label>
      <input id="places" name="places" type="number" required min="1" max="4" value="1">
    </p>
    <p>
      <label for="postcode">Postcode</label>
      <input id="postcode" name="postcode" type="text" required
             pattern="[A-Za-z]{1,2}[0-9][A-Za-z0-9]? ?[0-9][A-Za-z]{2}"
             aria-describedby="postcode-hint">
      <span id="postcode-hint">For example, BS1 4AB</span>
    </p>
    <button type="submit">Book</button>
  </form>
</body>
</html>

How pattern works

pattern takes a JavaScript regular expression. It must match the whole value, so you do not need ^ and $. An empty, optional field is not checked against the pattern; add required if it must be filled.

Modern browsers compile pattern with the regular expression v flag, which is stricter about some characters inside character classes. If a pattern that works elsewhere seems to be ignored, check the Console for a pattern error and escape characters such as - inside square brackets.

Always explain the expected format in visible text, as the postcode hint does. A pattern with no explanation leaves people guessing why their input is rejected. aria-describedby connects the hint to the field so screen readers read it too.

Styling valid and invalid fields

CSS can target the validation state:

  • :invalid and :valid match as soon as the page loads. A required, empty field is invalid immediately, so styling :invalid paints the whole form red before anyone has typed.
  • :user-invalid and :user-valid match only after the person has interacted with the field or tried to submit. That is almost always what you want.

:user-invalid is supported in all current major browsers. Check Baseline on web.dev if you need to support older versions. Do not rely on colour alone to show an error; the browser's message or your own text should say what is wrong.

Turning validation off

novalidate on the form turns off the browser's checks and messages while keeping the constraint attributes:

HTML
<form action="/book" method="post" novalidate>

Teams use this when they show their own error messages with JavaScript, using the same constraints through the Constraint Validation API (checkValidity(), validity and setCustomValidity()). Accessible custom error handling is covered in the Web Accessibility Essentials course.

Browser validation is a convenience, not security. Anyone can remove the attributes in DevTools or send a request directly. Validate every value again on the server.

Summary

  • Choose type by the data: email, url, tel, number, date, time and others.
  • Use number only for real quantities, never for phone or card numbers.
  • Add required, minlength, maxlength, min, max, step and pattern for built-in checks.
  • Explain expected formats in visible text, and style errors with :user-invalid.
  • Always validate again on the server.

Further reading