HTML Guides for maxlength
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 maxlength from any <input> whose type is not email, password, search, tel, text, or url.
- Use the correct constraint attributes for the input type in question. For number inputs, use min and max. For date inputs, use min and max with 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
<label for="quantity">Quantity</label>
<input type="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
<label for="quantity">Quantity</label>
<input type="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
<label for="start-date">Start date</label>
<input type="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
<label for="start-date">Start date</label>
<input type="date" id="start-date" name="start-date" min="2020-01-01" max="2030-12-31">
❌ Invalid: maxlength on a checkbox
<label>
<input type="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>
<input type="checkbox" name="agree"> I agree
</label>
✅ Valid: maxlength on supported text-based types
<label for="username">Username</label>
<input type="text" id="username" name="username" maxlength="30">
<label for="user-email">Email</label>
<input type="email" id="user-email" name="email" maxlength="254">
<label for="user-phone">Phone</label>
<input type="tel" id="user-phone" name="phone" maxlength="15">
<label for="site-url">Website</label>
<input type="url" id="site-url" name="website" maxlength="2048">
<label for="user-pass">Password</label>
<input type="password" id="user-pass" name="password" maxlength="128">
<label for="query">Search</label>
<input type="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 HTML specification defines maxlength as accepting only a valid non-negative integer — a string of one or more ASCII digits representing a number greater than or equal to zero. An empty string does not satisfy this requirement, so the W3C validator flags it as an error. This commonly happens when a value is dynamically generated by a CMS, template engine, or JavaScript framework and the value ends up blank, or when a developer adds the attribute as a placeholder intending to fill it in later.
Why this matters
While most browsers silently ignore an empty maxlength and impose no character limit, relying on this behavior is problematic for several reasons:
- Standards compliance: Invalid HTML can lead to unpredictable behavior across different browsers and versions. What works today may not work tomorrow.
- Accessibility: Assistive technologies may read or interpret the maxlength attribute to communicate input constraints to users. An empty value could cause confusing or incorrect announcements.
- Maintainability: An empty maxlength is ambiguous — it’s unclear whether the developer intended no limit, forgot to set a value, or a bug caused the value to be missing.
How to fix it
You have two options:
- Set a valid non-negative integer: Provide a concrete number that represents the maximum number of characters the user can enter, such as maxlength="100".
- Remove the attribute: If you don’t need to enforce a character limit, simply omit maxlength altogether. There is no need to include it with an empty value.
Valid values for maxlength include "0", "1", "255", or any other non-negative whole number. The following are not valid: empty strings (""), negative numbers ("-1"), decimal numbers ("10.5"), or non-numeric strings ("none").
Where maxlength applies
The maxlength attribute is meaningful on text-entry input types: text, search, url, tel, email, password, and also on the textarea element. For non-text input types like number, date, range, or checkbox, the attribute has no effect and should not be used.
Examples
❌ Incorrect: empty string triggers the validation error
<input type="text" name="username" maxlength="">
❌ Incorrect: other invalid values
<input type="text" name="username" maxlength="-1">
<input type="email" name="email" maxlength="none">
<input type="text" name="bio" maxlength="10.5">
✅ Correct: explicit maximum length
<input type="text" name="username" maxlength="30">
✅ Correct: omit the attribute when no limit is needed
<input type="text" name="comment">
✅ Correct: maxlength on a textarea
<textarea name="bio" maxlength="500"></textarea>
✅ Correct: dynamic value with a fallback
If your maxlength value comes from a template or CMS, make sure you either output a valid number or omit the attribute entirely. For example, in a templating language, use conditional logic:
<!-- Only render maxlength if the value is set -->
<input type="text" name="username" maxlength="100">
Rather than rendering an empty attribute like maxlength="", ensure your template skips the attribute when no value is configured.
The maxlength attribute controls the maximum number of characters a user can type into a <textarea>. According to the HTML specification, its value must be a valid non-negative integer — that is, a string of one or more ASCII digits like 0, 100, or 5000. An empty string (""), whitespace, negative numbers, or non-numeric values are all invalid. When the browser encounters an invalid maxlength value, its behavior becomes unpredictable — some browsers may ignore the attribute, while others may silently enforce no limit, leading to inconsistent form behavior across platforms.
This issue frequently arises when a server-side template or JavaScript framework conditionally outputs the maxlength attribute but produces an empty value when no limit is configured. For example, a template like maxlength="{{ maxChars }}" will render maxlength="" if the maxChars variable is empty or undefined. The fix is to ensure the attribute is omitted entirely when no value is available, rather than rendering it with an empty string.
Omitting maxlength allows unlimited input. Setting it to 0 is technically valid but prevents the user from entering any characters at all, which is rarely useful. Choose a value that makes sense for your use case, such as the corresponding database column’s character limit.
Why this matters
- Standards compliance: The HTML specification explicitly requires a valid non-negative integer. An empty string violates this rule and produces a validation error.
- Consistent behavior: Browsers handle invalid attribute values differently. A valid value ensures the character limit works reliably across all browsers.
- Accessibility: Screen readers and assistive technologies may announce the maximum character limit to users. An empty or invalid value could cause confusing announcements or be silently ignored.
- Form reliability: If your application depends on maxlength for client-side input restrictions (e.g., to match a database column limit), an invalid value means the constraint isn’t enforced, potentially leading to data truncation or server errors.
How to fix it
- Set a specific integer value if you need a character limit: maxlength="200".
- Remove the attribute entirely if no limit is needed. An absent maxlength means unlimited input.
- Fix your templates — if you’re using a server-side language or JavaScript framework, conditionally render the attribute so it’s omitted when no value is provided rather than output as empty.
Examples
❌ Invalid: empty maxlength value
The empty string is not a valid non-negative integer, so this triggers the validation error.
<label for="msg">Message</label>
<textarea id="msg" name="message" maxlength=""></textarea>
❌ Invalid: non-numeric maxlength value
Strings, decimals, and negative numbers are also invalid.
<label for="bio">Bio</label>
<textarea id="bio" name="bio" maxlength="none"></textarea>
<label for="notes">Notes</label>
<textarea id="notes" name="notes" maxlength="-1"></textarea>
✅ Fixed: specific integer value
Set maxlength to the desired character limit.
<label for="msg">Message (max 200 characters)</label>
<textarea id="msg" name="message" maxlength="200"></textarea>
✅ Fixed: attribute omitted entirely
If no character limit is needed, simply remove the attribute.
<label for="msg">Message</label>
<textarea id="msg" name="message"></textarea>
✅ Fixed: conditional rendering in a template
If you’re using a templating engine, conditionally include the attribute only when a value exists. The exact syntax depends on your framework — here’s a conceptual example:
<!-- Instead of always outputting the attribute: -->
<!-- <textarea maxlength="{{ maxChars }}"></textarea> -->
<!-- Only render it when maxChars has a value: -->
<!-- {% if maxChars %}<textarea maxlength="{{ maxChars }}"></textarea>{% endif %} -->
<label for="feedback">Feedback</label>
<textarea id="feedback" name="feedback" maxlength="500"></textarea>
When you write an attribute like maxlength="200 and accidentally omit the closing quote, everything that follows — including subsequent attribute names and their values — gets absorbed into that one attribute’s value. In this case, the validator sees the value of maxlength as 200 aria-required= (or similar), which is not a valid integer. The parser doesn’t encounter a closing " until it finds the next quotation mark further along in the tag, causing a cascade of errors.
This is a problem for several reasons:
- Broken functionality: The maxlength attribute won’t work because 200 aria-required= is not a valid number. The browser cannot determine the intended character limit.
- Lost attributes: The aria-required attribute is swallowed into the malformed maxlength value, so it never gets applied as a separate attribute. Assistive technologies like screen readers won’t know the field is required.
- Accessibility impact: Since aria-required="true" is lost, users who rely on screen readers won’t receive the information that the field is mandatory, potentially leading to form submission errors and a frustrating experience.
The root cause is almost always a missing closing quotation mark. Carefully check that every attribute value has both an opening and a closing ". This kind of typo is easy to make and easy to miss, especially in long tags with many attributes.
Examples
Incorrect — missing closing quote on maxlength
The closing " after 200 is missing, so the value of maxlength extends all the way to the next quotation mark it finds:
<input type="text" name="nome" id="nome" maxlength="200 aria-required="true">
The validator interprets maxlength as having the value 200 aria-required=, and only true ends up as the value of an unintended or malformed attribute. Nothing works as expected.
Correct — properly quoted attributes
Each attribute has its own properly matched pair of quotation marks:
<input type="text" name="nome" id="nome" maxlength="200" aria-required="true">
Here, maxlength="200" correctly limits the input to 200 characters, and aria-required="true" is a separate attribute that tells assistive technologies the field is required.
Incorrect — missing closing quote with more attributes
This issue can happen with any combination of attributes. Here, a missing quote after maxlength absorbs class and placeholder:
<input type="text" maxlength="50 class="username" placeholder="Enter name">
Correct — all quotes properly closed
<input type="text" maxlength="50" class="username" placeholder="Enter name">
Tips for avoiding this issue
- Use a code editor with syntax highlighting. Most editors color attribute values differently from attribute names. If you see an attribute name rendered in the same color as a value string, a quote is likely missing.
- Format attributes one per line on complex elements. This makes it much easier to spot mismatched quotes:
<input
type="text"
name="nome"
id="nome"
maxlength="200"
aria-required="true">
- Validate early and often. Running your HTML through the W3C validator regularly helps catch these small typos before they cause confusing bugs in production.
Ready to validate your sites?
Start your free trial today.