HTML Guides for text
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The maxlength attribute provides built-in client-side validation that caps the number of characters a user can type into a field. Browsers enforce this by preventing further input once the limit is reached. However, this behavior only makes sense for input types that accept arbitrary text strings. Input types like number, date, range, and checkbox have their own value formats and constraints — a number input's value is controlled by min, max, and step, not by character count.
When you place maxlength on an unsupported input type, browsers will ignore the attribute. This means it provides no actual validation while giving a false sense of security. It also produces invalid HTML, which can cause issues with assistive technologies that may try to interpret the attribute and relay incorrect information to users. Keeping your markup valid ensures predictable behavior across browsers and a better experience for all users.
How to fix it
- Remove
maxlengthfrom any<input>whosetypeis notemail,password,search,tel,text, orurl. - Use the correct constraint attributes for the input type in question. For
numberinputs, useminandmax. Fordateinputs, useminandmaxwith date strings. - If you genuinely need character-length validation, consider whether a text-based input type is more appropriate for your use case, or implement the constraint in JavaScript.
Examples
❌ Invalid: maxlength on a number input
<labelfor="quantity">Quantity</label>
<inputtype="number"id="quantity"name="quantity"maxlength="3">
The number type does not support maxlength. Browsers will ignore it, and the HTML is invalid.
✅ Fixed: using min and max for a number input
<labelfor="quantity">Quantity</label>
<inputtype="number"id="quantity"name="quantity"min="0"max="999">
If the goal was to limit the value to three digits, min and max are the correct constraints.
❌ Invalid: maxlength on a date input
<labelfor="start-date">Start date</label>
<inputtype="date"id="start-date"name="start-date"maxlength="10">
Date inputs have a browser-provided date picker, and their values are always in YYYY-MM-DD format. The maxlength attribute has no effect here.
✅ Fixed: using min and max for a date input
<labelfor="start-date">Start date</label>
<inputtype="date"id="start-date"name="start-date"min="2020-01-01"max="2030-12-31">
❌ Invalid: maxlength on a checkbox
<label>
<inputtype="checkbox"name="agree"maxlength="1"> I agree
</label>
A checkbox is a boolean toggle — character length is meaningless here.
✅ Fixed: removing the invalid attribute
<label>
<inputtype="checkbox"name="agree"> I agree
</label>
✅ Valid: maxlength on supported text-based types
<labelfor="username">Username</label>
<inputtype="text"id="username"name="username"maxlength="30">
<labelfor="user-email">Email</label>
<inputtype="email"id="user-email"name="email"maxlength="254">
<labelfor="user-phone">Phone</label>
<inputtype="tel"id="user-phone"name="phone"maxlength="15">
<labelfor="site-url">Website</label>
<inputtype="url"id="site-url"name="website"maxlength="2048">
<labelfor="user-pass">Password</label>
<inputtype="password"id="user-pass"name="password"maxlength="128">
<labelfor="query">Search</label>
<inputtype="search"id="query"name="q"maxlength="100">
All six of these input types support maxlength because they accept free-form text where limiting character count is meaningful.
The minlength attribute defines the minimum number of characters (as UTF-16 code units) that a user can enter into a text-based input field. It provides built-in client-side validation without requiring JavaScript. However, it only makes sense on input types where the user is typing free-form text. For input types like number, date, color, range, or checkbox, the concept of a minimum character length doesn't apply — these inputs have their own constrained value formats or use other attributes like min and max for validation.
When the W3C validator encounters minlength on an unsupported input type, it flags the attribute as invalid. Browsers will typically ignore the attribute silently, meaning your intended validation won't actually work. This can lead to a false sense of security where you believe the input is being validated when it isn't.
The minlength value must be a non-negative integer (0 or higher) and must be less than or equal to maxlength if both are specified. The minlength attribute also works on <textarea> elements.
Examples
❌ Incorrect: minlength on a number input
The number input type doesn't support minlength. If you want to enforce a minimum value, use the min attribute instead.
<labelfor="age">Enter your age</label>
<inputtype="number"minlength="1"id="age">
✅ Fixed: Using min for number inputs
<labelfor="age">Enter your age</label>
<inputtype="number"min="1"id="age">
❌ Incorrect: minlength on a date input
<labelfor="start-date">Start date</label>
<inputtype="date"minlength="10"id="start-date">
✅ Fixed: Remove minlength from date inputs
Date inputs have a browser-controlled format, so character length constraints don't apply. Use min and max to constrain the date range.
<labelfor="start-date">Start date</label>
<inputtype="date"min="2024-01-01"id="start-date">
✅ Correct: minlength on supported input types
Here are valid uses of minlength across all supported input types:
<labelfor="username">Username (at least 3 characters)</label>
<inputtype="text"minlength="3"id="username">
<labelfor="email">Email</label>
<inputtype="email"minlength="5"id="email">
<labelfor="pass">Password (at least 8 characters)</label>
<inputtype="password"minlength="8"id="pass">
<labelfor="phone">Phone number</label>
<inputtype="tel"minlength="7"id="phone">
<labelfor="query">Search</label>
<inputtype="search"minlength="2"id="query">
<labelfor="website">Website URL</label>
<inputtype="url"minlength="10"id="website">
✅ Correct: minlength with maxlength on a textarea
<labelfor="bio">Bio (between 10 and 200 characters)</label>
<textareaminlength="10"maxlength="200"id="bio"></textarea>
Quick Reference
| Input Type | Supports minlength? | Alternative |
|---|---|---|
text, email, password, search, tel, url | ✅ Yes | — |
textarea | ✅ Yes | — |
number, range | ❌ No | Use min / max |
date, datetime-local, time, month, week | ❌ No | Use min / max |
checkbox, radio | ❌ No | Use required |
file | ❌ No | Validate with JavaScript |
color, hidden | ❌ No | Not applicable |
The pattern attribute provides a powerful way to add client-side form validation directly in HTML without relying on JavaScript. It accepts a regular expression that the browser uses to validate user input before the form is submitted. However, the HTML specification restricts pattern to input types where the user enters free-form text. Input types like number, date, range, color, and checkbox have their own built-in validation mechanisms (such as min, max, and step), so applying a regex pattern to them is meaningless and invalid.
When you add pattern to an unsupported input type, browsers will simply ignore it. This means you might think you have validation in place when you actually don't, which can lead to unexpected invalid data being submitted. Removing the invalid attribute also keeps your markup clean and standards-compliant, which benefits accessibility tools and future browser behavior.
Why certain types don't support pattern
number— Values are constrained bymin,max, andstep. The browser enforces numeric input natively.date,time,datetime-local,month,week— These use date/time pickers with their own format and range constraints.range— A slider control already constrained bymin,max, andstep.checkbox,radio— These are toggled on/off or selected from a group; a regex pattern doesn't apply.file— File selection is handled by the OS file picker; use theacceptattribute instead.color— Uses a color picker with a fixed hex format.hidden— Not user-editable, so client-side validation is irrelevant.
How to fix it
- Remove the
patternattribute if the input type already provides sufficient validation through its native controls. - Change the input
typeto one of the six supported types (email,password,search,tel,text, orurl) if you genuinely need regex-based validation. - Use alternative attributes like
min,max,step, oracceptthat are designed for the specific input type. - Use JavaScript validation if you need custom validation logic that goes beyond what native attributes offer.
Examples
❌ Incorrect: pattern on a number input
<labelfor="qty">Quantity (multiples of 5):</label>
<inputtype="number"id="qty"name="qty"pattern="[0-9]+"min="0"max="100">
The pattern attribute is not allowed on type="number". Since min, max, and step already handle numeric constraints, pattern is unnecessary here.
✅ Correct: using step instead of pattern for number validation
<labelfor="qty">Quantity (multiples of 5):</label>
<inputtype="number"id="qty"name="qty"min="0"max="100"step="5">
❌ Incorrect: pattern on a date input
<labelfor="dob">Date of birth:</label>
<inputtype="date"id="dob"name="dob"pattern="\d{4}-\d{2}-\d{2}">
The date input type already enforces a date format through its native picker, so pattern is invalid here.
✅ Correct: removing pattern from date input
<labelfor="dob">Date of birth:</label>
<inputtype="date"id="dob"name="dob"min="1900-01-01"max="2025-12-31">
❌ Incorrect: pattern on a checkbox input
<label>
<inputtype="checkbox"name="agree"pattern=".+"> I agree to the terms
</label>
✅ Correct: using required instead of pattern for checkbox
<label>
<inputtype="checkbox"name="agree"required> I agree to the terms
</label>
✅ Correct: pattern on a supported text input
<labelfor="zip">ZIP code:</label>
<inputtype="text"id="zip"name="zip"pattern="[0-9]{5}"title="Five digit ZIP code"required>
When using pattern on a supported input type, always include a title attribute that describes the expected format. Browsers display the title text as part of the validation error message, helping users understand what input is expected.
The required attribute is a boolean attribute that tells the browser a field must be filled in before the form can be submitted. However, not every input type supports this concept. Some input types always have a value (like range, which defaults to a midpoint, or color, which defaults to #000000), while others represent actions rather than user data (like submit, reset, image, and button). For hidden inputs, the user has no way to interact with the field at all, so requiring them to provide a value makes no sense.
The HTML specification explicitly limits required to the following input types: checkbox, date, datetime-local, email, file, month, number, password, radio, search, tel, text, time, url, and week.
Using required on an unsupported type is invalid HTML. Browsers will typically ignore the attribute in this situation, which means you might believe a field is required when it actually isn't being validated at all. This can lead to forms being submitted with missing or unexpected data. It also creates confusion for assistive technologies — screen readers may announce a field as required even though the browser won't enforce it, misleading users.
How to fix it
- Check the input type. If you're using
requiredon an input with a type likehidden,range,color,submit,reset,image, orbutton, the attribute is not allowed. - Remove the
requiredattribute if the input type inherently provides a value or doesn't accept user-provided data. - Change the input type if you actually need the field to be required and the current type doesn't match your intent.
- Use server-side validation for inputs like
hiddenthat can't userequiredbut still need a value.
Examples
❌ Invalid: required on a hidden input
<form>
<inputtype="hidden"name="token"required>
<buttontype="submit">Submit</button>
</form>
The user cannot interact with a hidden input, so required is not allowed here. The browser won't enforce it.
❌ Invalid: required on a range input
<form>
<labelfor="volume">Volume:</label>
<inputtype="range"id="volume"name="volume"min="0"max="100"required>
<buttontype="submit">Submit</button>
</form>
A range input always has a value (it defaults to the midpoint), so required is meaningless and not permitted.
❌ Invalid: required on a color input
<form>
<labelfor="color">Pick a color:</label>
<inputtype="color"id="color"name="color"required>
<buttontype="submit">Submit</button>
</form>
A color input always has a value (defaulting to #000000), so required is not valid here.
✅ Valid: required removed from unsupported types
<form>
<inputtype="hidden"name="token"value="abc123">
<labelfor="volume">Volume:</label>
<inputtype="range"id="volume"name="volume"min="0"max="100">
<buttontype="submit">Submit</button>
</form>
✅ Valid: required on supported input types
<form>
<labelfor="email">Email:</label>
<inputtype="email"id="email"name="email"required>
<labelfor="dob">Date of birth:</label>
<inputtype="date"id="dob"name="dob"required>
<label>
<inputtype="checkbox"name="terms"required>
I agree to the terms
</label>
<buttontype="submit">Submit</button>
</form>
These input types — email, date, and checkbox — all accept direct user input and are on the allowed list for the required attribute.
The HTML <input> element's type attribute only accepts a specific set of predefined values defined in the HTML specification. These include values like text, password, email, number, date, datetime-local, checkbox, radio, and others. The value dob — presumably short for "date of birth" — is not among them.
When a browser encounters an invalid type value, it doesn't throw an error or prevent the page from loading. Instead, it treats the input as type="text". This means the input might appear to work, but you lose important benefits: there's no native date picker UI, no built-in date format validation, and no appropriate mobile keyboard. The W3C validator flags this to help you catch the mistake early.
This matters for several reasons:
- Accessibility: Valid input types provide semantic meaning to assistive technologies. A
type="date"input tells screen readers that a date is expected, enabling better guidance for users. - User experience: Native date inputs offer platform-appropriate date pickers on mobile and desktop, reducing input errors.
- Standards compliance: Using invalid attribute values produces unpredictable behavior across browsers and can break future compatibility.
To fix this issue, replace type="dob" with a recognized type. For a date of birth field, type="date" is the most appropriate choice. If you need more control over formatting, you can use type="text" with a JavaScript date picker library or custom validation.
Examples
❌ Invalid: using type="dob"
<labelfor="dob">Date of Birth:</label>
<inputtype="dob"id="dob"name="dob">
The browser will treat this as a plain text input, and the W3C validator will report: Bad value "dob" for attribute "type" on element "input".
✅ Fixed: using type="date"
<labelfor="dob">Date of Birth:</label>
<inputtype="date"id="dob"name="dob">
This uses the native HTML date input, which provides a built-in date picker in most modern browsers. You can also constrain the date range with min and max attributes:
<labelfor="dob">Date of Birth:</label>
<inputtype="date"id="dob"name="dob"min="1900-01-01"max="2025-12-31">
✅ Fixed: using type="text" with a JavaScript date picker
If you need more control over the date picker's appearance or need to support older browsers that lack native date input support, use type="text" and enhance it with JavaScript:
<labelfor="dob">Date of Birth:</label>
<inputtype="text"id="dob"name="dob"placeholder="YYYY-MM-DD">
You can then attach a JavaScript date picker library (such as Flatpickr, Pikaday, or a framework-specific component) to this input for a custom date selection experience. When using this approach, make sure to add appropriate aria-* attributes and validation to maintain accessibility.
Valid type values for reference
Here are some commonly used valid type values for the <input> element:
text— plain text inputdate— date picker (year, month, day)datetime-local— date and time picker (no timezone)month— month and year pickernumber— numeric inputemail— email address inputtel— telephone number inputpassword— masked text input
Always choose the type that best matches the data you're collecting. For a date of birth, type="date" is the most semantically correct and user-friendly option.
The HTML specification defines specific rules about which autocomplete autofill field names can be paired with which input types. The tel-national token (which represents a phone number without the country code) is classified as requiring a text-based input control. Meanwhile, <input type="tel"> is a specialized control that the spec treats differently from a plain text field. When the validator encounters tel-national on a type="tel" input, it flags the mismatch because the autofill field name is not allowed in that context.
This might seem counterintuitive — a national telephone number value on a telephone input feels like a natural fit. However, the distinction exists because type="tel" already implies a complete telephone number, and the spec maps the broader tel autocomplete token to it. The more granular telephone tokens like tel-national, tel-country-code, tel-area-code, tel-local, tel-local-prefix, and tel-local-suffix are designed for type="text" inputs where a phone number is being broken into individual parts across multiple fields.
Getting this right matters for browser autofill behavior. When the autocomplete value and input type are properly paired according to the spec, browsers can more reliably populate the field with the correct portion of the user's stored phone number. An invalid pairing may cause autofill to silently fail or behave unpredictably across different browsers.
How to fix it
You have two options:
- Change the input type to
text— Usetype="text"if you specifically want the national portion of a phone number (without the country code). This is the right choice when you're splitting a phone number across multiple fields. - Change the autocomplete value to
tel— Useautocomplete="tel"if you want a single field for the full phone number. This pairs correctly withtype="tel".
Examples
❌ Invalid: tel-national on type="tel"
<labelfor="phone">Phone number</label>
<inputid="phone"name="phone"type="tel"autocomplete="tel-national">
This triggers the validation error because tel-national is not allowed on a type="tel" input.
✅ Fix option 1: Change input type to text
<labelfor="phone">Phone number (without country code)</label>
<inputid="phone"name="phone"type="text"autocomplete="tel-national">
Using type="text" satisfies the spec's requirement for the tel-national autofill token. This is ideal when collecting just the national portion of a number.
✅ Fix option 2: Change autocomplete to tel
<labelfor="phone">Phone number</label>
<inputid="phone"name="phone"type="tel"autocomplete="tel">
Using autocomplete="tel" is the correct pairing for type="tel" and tells the browser to autofill the complete phone number.
✅ Splitting a phone number across multiple fields
When you need separate fields for different parts of a phone number, use type="text" with the granular autocomplete tokens:
<fieldset>
<legend>Phone number</legend>
<labelfor="country-code">Country code</label>
<inputid="country-code"name="country-code"type="text"autocomplete="tel-country-code">
<labelfor="national">National number</label>
<inputid="national"name="national"type="text"autocomplete="tel-national">
</fieldset>
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
Pro Trial
Full Pro access. Cancel anytime.
Start Pro Trial →Join teams across 40+ countries