HTML Guides for search
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 search ARIA role is a landmark role, which means it identifies a large, navigable section of a page — specifically, the region that contains the search functionality. Landmark roles help assistive technologies (like screen readers) quickly identify and jump to major sections of a document. Because landmarks describe sections of a page, they belong on container elements that encompass all the parts of the search interface (the label, the input field, the submit button, etc.), not on a single <input> element.
When you place role="search" on an <input>, the validator rejects it because the search role doesn't match the semantics of an input control. An <input> represents a single interactive widget, not a page region. The valid way to indicate that an input field is for search queries is to use <input type="search">, which gives browsers and assistive technologies the correct semantic meaning for that specific control.
Meanwhile, if you want to mark an entire search form as a search landmark, apply role="search" to the <form> element that wraps the search controls. In modern HTML, you can also use the <search> element, which has the implicit search landmark role without needing any ARIA attribute.
How to fix it
- Remove
role="search"from the<input>element. - Change the input's
typeto"search"— this tells browsers and assistive technologies that the field is for search queries. - Apply
role="search"to the wrapping<form>, or use the HTML<search>element as the container.
Examples
❌ Incorrect: role="search" on an <input>
<form>
<labelfor="query">Search</label>
<inputrole="search"id="query"name="q">
<buttontype="submit">Go</button>
</form>
This triggers the validation error because search is not a valid role for <input>.
✅ Correct: type="search" on the input, role="search" on the form
<formrole="search">
<labelfor="query">Search this site</label>
<inputtype="search"id="query"name="q">
<buttontype="submit">Go</button>
</form>
Here, role="search" is correctly placed on the <form> element, creating a search landmark. The <input type="search"> conveys the correct semantics for the input field itself.
✅ Correct: Using the <search> element (modern HTML)
<search>
<form>
<labelfor="query">Search this site</label>
<inputtype="search"id="query"name="q">
<buttontype="submit">Go</button>
</form>
</search>
The <search> element has the implicit ARIA role of search, so no explicit role attribute is needed on either the container or the form. This is the most semantic approach in browsers that support it.
✅ Correct: Standalone search input without a landmark
If you simply need a search-styled input without marking up a full landmark region, just use type="search":
<labelfor="filter">Filter results</label>
<inputtype="search"id="filter"name="filter">
This gives the input the correct semantics and allows browsers to provide search-specific UI features (such as a clear button) without requiring a landmark role.
Every HTML element carries an implicit ARIA role based on its type and attributes. For <input type="search"> elements that do not have a list attribute, the browser automatically exposes the element with the searchbox role to assistive technologies. This mapping is defined in the ARIA in HTML specification, which establishes the correspondence between native HTML semantics and ARIA roles.
When you explicitly add role="searchbox" to an element that already carries that role implicitly, the validator raises a warning because the attribute is doing nothing useful. While it won't break functionality, redundant roles clutter your markup and can signal to other developers (or future you) that something special is intended when it isn't. Following the general principle of ARIA — "don't use ARIA if you can use native HTML" — also means not restating what the browser already communicates.
Note the distinction the validator makes: this applies specifically to <input type="search"> elements without a list attribute. When a list attribute is present (linking the input to a <datalist>), the implicit role changes to combobox, so in that specific scenario the implicit role is different. However, for a plain search input without list, the searchbox role is already baked in.
Why it matters
- Standards compliance: The W3C validator flags redundant roles to encourage clean, semantic markup that relies on native HTML behavior.
- Maintainability: Redundant attributes add noise. Other developers may wonder why the role was explicitly set and whether removing it would break something.
- ARIA best practices: The first rule of ARIA is to use native HTML semantics whenever possible. Restating implicit roles goes against this principle and can mask situations where an explicit role would actually be meaningful.
How to fix it
Simply remove the role="searchbox" attribute from any <input type="search"> element that does not have a list attribute. The browser and assistive technologies will continue to treat it as a search box.
Examples
Incorrect — redundant role
The role="searchbox" is unnecessary here because <input type="search"> already implies it:
<labelfor="site-search">Search the site:</label>
<inputtype="search"id="site-search"role="searchbox"placeholder="Search...">
Correct — relying on implicit role
Remove the redundant role attribute and let native HTML semantics do the work:
<labelfor="site-search">Search the site:</label>
<inputtype="search"id="site-search"placeholder="Search...">
Correct — explicit role when implicit role differs
When a list attribute is present, the implicit role changes to combobox. If you want assistive technologies to treat it as a searchbox instead, an explicit role is justified:
<labelfor="city-search">Search cities:</label>
<inputtype="search"id="city-search"list="cities"role="searchbox">
<datalistid="cities">
<optionvalue="Amsterdam">
<optionvalue="Berlin">
<optionvalue="Cairo">
</datalist>
In this case, the validator will not flag the role as redundant because the implicit role (combobox) differs from the explicitly set role (searchbox).
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