HTML Guides
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 dir attribute cannot be an empty string — it must be one of the allowed values: ltr, rtl, or auto.
The dir attribute specifies the text directionality of an element's content. It is a global attribute, meaning it can be used on any HTML element. When you set dir="", the validator rejects it because an empty string doesn't convey any meaningful direction.
If you don't need to specify a direction, simply remove the dir attribute entirely. The element will naturally inherit the directionality from its parent. If you want the browser to determine the direction based on the text content, use dir="auto".
Invalid Example
<spandir="">Some text</span>
Valid Examples
<!-- Remove the attribute to inherit direction from the parent -->
<span>Some text</span>
<!-- Or explicitly set a valid direction -->
<spandir="ltr">Some text</span>
<!-- Or let the browser decide based on content -->
<spandir="auto">Some text</span>
The for attribute on a <label> element tells the browser which form control the label describes. When a user clicks or taps the label, the browser transfers focus to the associated control. For this to work, the value of for must exactly match the id of a form element such as an <input>, <textarea>, <select>, or <button>.
An empty string ("") is not a valid ID according to the HTML specification. The WHATWG HTML standard requires that an id attribute value must contain at least one character and must not contain ASCII whitespace. Since no element can have an empty-string id, a <label> with for="" can never successfully reference anything, making it both invalid markup and a broken association.
Why this matters
Accessibility: Screen readers rely on the for/id pairing to announce what a form control is for. A label with an empty for attribute creates no programmatic association, meaning assistive technology users may not know what a field is asking for. This directly impacts WCAG compliance.
Usability: A properly associated label expands the clickable area of its form control. For example, clicking a label associated with a checkbox will toggle the checkbox. An empty for attribute breaks this behavior.
Standards compliance: The W3C validator flags this because it violates the HTML specification. Keeping markup valid helps ensure consistent behavior across browsers and future-proofs your code.
How to fix
You have three options:
- Set
forto a validid: Give the associated form control a uniqueidand reference it in the label'sforattribute. - Remove
forand use implicit association: Wrap the form control inside the<label>element. This creates an implicit association without needingfororidat all. - Remove the
forattribute: If the label is purely decorative or not meant to be associated with a control, simply remove the emptyforattribute.
Examples
❌ Empty for attribute (triggers the error)
<labelfor="">Username:</label>
<inputtype="text"name="username">
The label has no meaningful association with the input because for="" is not a valid reference.
✅ Fix: Use a valid for/id pair
<labelfor="username">Username:</label>
<inputtype="text"id="username"name="username">
The for="username" now matches id="username" on the input, creating an explicit association.
✅ Fix: Use implicit association by nesting
<label>
Username:
<inputtype="text"name="username">
</label>
Wrapping the input inside the <label> creates an implicit association. No for or id attributes are needed.
❌ Multiple labels with empty for attributes
<form>
<labelfor="">Email:</label>
<inputtype="email"name="email">
<labelfor="">Subscribe to newsletter</label>
<inputtype="checkbox"name="subscribe">
</form>
✅ Fixed with proper associations
<form>
<labelfor="email">Email:</label>
<inputtype="email"id="email"name="email">
<labelfor="subscribe">Subscribe to newsletter</label>
<inputtype="checkbox"id="subscribe"name="subscribe">
</form>
Each id must be unique within the document, and each for attribute must reference exactly one id. If your labels are generated by a framework or CMS with empty for values, check the template or component configuration to ensure proper id values are being output.
In a URL, the # character has a special role: it acts as the delimiter that separates the main URL from the fragment identifier. The fragment typically points to a specific section or element within the target document, often corresponding to an element's id attribute. Because # serves this reserved purpose, it cannot appear more than once in its raw form within a URL. When the validator encounters something like ##pricing or section#one#two, it flags the extra # characters as illegal.
This issue usually arises from one of these common scenarios:
- Typos — accidentally typing
##instead of#. - String concatenation bugs — building URLs programmatically where a
#is included both in the base URL and prepended to the fragment value. - Copy-paste errors — duplicating the
#when copying URLs from browser address bars or other sources. - Literal
#intended in fragment — if you genuinely need a#symbol within the fragment text, it must be percent-encoded as%23.
This matters because browsers may handle malformed URLs inconsistently. Some browsers silently strip the extra #, while others may fail to navigate to the intended fragment. Malformed URLs also cause problems for assistive technologies, web crawlers, and any tooling that parses links. Keeping your URLs well-formed ensures predictable behavior across all user agents and complies with the URL Standard and HTML specification.
Examples
Incorrect: duplicate # in the URL
The double ## makes the fragment identifier invalid:
<ahref="https://example.com/faqs##pricing">Pricing</a>
Correct: single # delimiter
Remove the extra # so that pricing is the fragment:
<ahref="https://example.com/faqs#pricing">Pricing</a>
Incorrect: extra # inside the fragment
Here, the fragment portion overview#details contains a raw #, which is not allowed:
<ahref="/docs#overview#details">Details</a>
Correct: percent-encode the literal #
If you truly need a # as part of the fragment text, encode it as %23:
<ahref="/docs#overview%23details">Details</a>
In most cases though, this pattern suggests the URL structure should be rethought. A cleaner approach is to link directly to the intended fragment:
<ahref="/docs#details">Details</a>
Incorrect: programmatic concatenation error
A common bug in templates or JavaScript is prepending # when the variable already includes it:
<!-- If defined as defined as fragment = "#pricing", this produces a double ## -->
<ahref="https://example.com/faqs#pricing">Pricing</a>
Correct: ensure only one # is present
Make sure either the base URL or the fragment variable includes the #, but not both:
<ahref="https://example.com/faqs#pricing">Pricing</a>
Fragment-only links
Fragment-only links (links to sections within the same page) follow the same rule — only one #:
<!-- Incorrect -->
<ahref="##contact">Contact Us</a>
<!-- Correct -->
<ahref="#contact">Contact Us</a>
A | (pipe) character in the fragment portion of a URL must be percent-encoded as %7C to be valid.
The href attribute on an <a> element must contain a valid URL. According to the URL specification, certain characters — including the pipe | — are not permitted as literal characters in a URL fragment (the part after #). The W3C validator flags this because the browser may handle it inconsistently, and it violates the URL standard.
To fix it, replace every | in the URL with its percent-encoded equivalent: %7C.
HTML Examples
❌ Invalid: literal pipe in fragment
<ahref="https://example.com/page#section|one">Link</a>
✅ Valid: percent-encoded pipe in fragment
<ahref="https://example.com/page#section%7Cone">Link</a>
If you control the target page, consider redesigning the fragment identifiers to avoid special characters altogether — for example, using hyphens or underscores like #section-one instead.
A URL fragment identifier is the part of a URL that follows the # character. It typically points to an element on the page that has a matching id attribute. According to the URL specification, certain characters — including spaces — are not allowed to appear literally in a URL. When the W3C HTML Validator encounters a raw space in a fragment, it reports this as an illegal character.
This issue matters for several reasons. Browsers may handle unescaped spaces in fragments inconsistently, leading to broken in-page navigation. Screen readers and other assistive technologies rely on well-formed URLs to navigate users to the correct section of a page. Additionally, spaces in id attributes are themselves invalid in HTML — the id attribute must not contain any ASCII whitespace characters. So the root cause often involves two separate violations: an invalid id and an invalid fragment URL.
The best approach is to use hyphens (-) or underscores (_) instead of spaces in your id values, then match the fragment accordingly. This produces clean, readable, and shareable URLs (e.g., page.html#contact-info instead of page.html#contact%20info). If you're working with a CMS or build tool that auto-generates id values with spaces, configure it to produce hyphen-separated, lowercase identifiers instead.
If you absolutely cannot change the id values (e.g., they're generated by a third-party system), you can percent-encode the spaces as %20 in the href. This satisfies URL syntax rules, but note that an id containing spaces is still invalid HTML on its own. Fixing the id is always the preferred solution.
Examples
Invalid: space in fragment and id
This triggers the validator error because href="#My Section" contains an unescaped space. The id="My Section" is also invalid HTML since id values cannot contain spaces.
<ahref="#My Section">Go to section</a>
<h2id="My Section">My Section</h2>
Fixed: hyphen-separated fragment and id
Replace spaces with hyphens in both the id and the fragment. This is the cleanest and most widely recommended approach.
<ahref="#my-section">Go to section</a>
<h2id="my-section">My Section</h2>
Fixed: underscore-separated fragment and id
Underscores work equally well if you prefer that convention.
<ahref="#my_section">Go to section</a>
<h2id="my_section">My Section</h2>
Alternative: percent-encoding the space
Encoding the space as %20 resolves the fragment URL error, but the id with a space is still invalid HTML. Use this only as a last resort when you cannot control the id values.
<ahref="#My%20Section">Go to section</a>
<!-- Note: this id is still invalid HTML due to the space -->
<h2id="My Section">My Section</h2>
Full valid document
A complete example demonstrating multiple in-page links with properly formatted fragments and id values:
<!doctype html>
<htmllang="en">
<head>
<title>Page sections</title>
</head>
<body>
<nav>
<ul>
<li><ahref="#getting-started">Getting Started</a></li>
<li><ahref="#advanced-usage">Advanced Usage</a></li>
<li><ahref="#frequently-asked-questions">FAQ</a></li>
</ul>
</nav>
<h2id="getting-started">Getting Started</h2>
<p>Introduction content here.</p>
<h2id="advanced-usage">Advanced Usage</h2>
<p>Advanced content here.</p>
<h2id="frequently-asked-questions">Frequently Asked Questions</h2>
<p>FAQ content here.</p>
</body>
</html>
URLs follow strict syntax rules defined by RFC 3986. Only a specific set of characters are allowed directly in a URL path segment — these include letters, digits, hyphens (-), periods (.), underscores (_), and tildes (~), along with a handful of sub-delimiters like !, $, &, ', (, ), *, +, ,, ;, and =. Any character outside this set — including spaces, angle brackets (< >), curly braces ({ }), pipe characters (|), backslashes (\), carets (^), and backticks (`) — must be percent-encoded.
Percent-encoding replaces the character with a % sign followed by its two-digit hexadecimal ASCII code. For example:
| Character | Percent-encoded |
|---|---|
| (space) | %20 |
{ | %7B |
} | %7D |
| ` | ` |
< | %3C |
> | %3E |
^ | %5E |
This validation error matters for several reasons. First, browsers may handle illegal characters inconsistently — some may silently encode them, while others may break the link or navigate to an unexpected destination. Second, tools that parse HTML (screen readers, search engine crawlers, link checkers) rely on well-formed URLs and may fail or behave unpredictably when they encounter illegal characters. Third, standards compliance ensures your HTML works reliably across all environments.
Common causes of this error include:
- Copying and pasting URLs from documents or emails that contain unencoded spaces or special characters.
- Template variables or placeholders left in
hrefvalues (e.g.,{{url}}). - File paths with spaces used directly as URLs without encoding.
- Non-ASCII characters in URLs that haven't been properly encoded.
Examples
❌ Space in the URL path
<ahref="/my page/about us.html">About Us</a>
✅ Spaces percent-encoded as %20
<ahref="/my%20page/about%20us.html">About Us</a>
❌ Curly braces from a template placeholder left in the markup
<ahref="/products/{{product-id}}/details">View Details</a>
✅ Curly braces replaced with an actual value
<ahref="/products/42/details">View Details</a>
❌ Pipe character in the path
<ahref="/search/color|size">Filter Results</a>
✅ Pipe character percent-encoded as %7C
<ahref="/search/color%7Csize">Filter Results</a>
❌ Angle brackets in the URL
<ahref="/page/<section>">Go to Section</a>
✅ Angle brackets percent-encoded
<ahref="/page/%3Csection%3E">Go to Section</a>
How to Fix
- Identify the illegal character from the validator's error message — it typically tells you exactly which character is problematic.
- Replace it with the correct percent-encoded equivalent using the table above or a URL encoder tool.
- If the URL contains template syntax (like
{{...}}), make sure your templating engine processes it before the HTML is served to the browser. The raw template syntax should never appear in the final rendered HTML. - Consider renaming files and directories to avoid spaces and special characters altogether — this is the cleanest long-term solution.
If you're generating URLs programmatically, use built-in encoding functions like JavaScript's encodeURIComponent() or PHP's rawurlencode() to ensure all special characters are properly escaped before inserting them into href attributes.
The W3C HTML Validator checks that URLs used in attributes like href conform to the URL Standard maintained by WHATWG. According to this standard, only certain characters are permitted to appear literally in the query component of a URL. The pipe character (|, Unicode U+007C) is not in the set of allowed query characters, which means it must be percent-encoded as %7C when it appears in a URL's query string.
While most modern browsers will silently handle a raw | in a URL and still navigate to the intended destination, relying on this behavior is problematic for several reasons:
- Standards compliance: HTML documents that contain unencoded special characters in URLs are technically invalid and will fail W3C validation.
- Interoperability: Not all user agents, HTTP clients, web scrapers, or proxy servers handle illegal URL characters the same way. An unencoded pipe could be misinterpreted, stripped, or cause unexpected behavior in certain environments.
- Security: Properly encoding URLs helps prevent injection attacks and ensures that each part of the URL is unambiguously parsed. Unencoded special characters can be exploited in certain contexts.
- Link sharing and processing: URLs are often copied, pasted, embedded in emails, or processed by APIs. An unencoded
|may break the URL when it passes through systems that strictly enforce URL syntax.
This issue commonly arises when URLs are constructed by hand, pulled from databases, or generated by backend systems that don't automatically encode query parameters. It can also appear when using pipe-delimited values as query parameter values (e.g., ?filter=red|blue|green).
The fix is straightforward: replace every literal | in the URL with its percent-encoded equivalent %7C. If you're generating URLs in code, use built-in encoding functions like JavaScript's encodeURIComponent() or PHP's urlencode() to handle this automatically.
Examples
Incorrect: raw pipe character in query string
<ahref="https://example.com/search?q=test|demo">Search</a>
The literal | in the query string triggers the validation error.
Correct: pipe character percent-encoded
<ahref="https://example.com/search?q=test%7Cdemo">Search</a>
Replacing | with %7C makes the URL valid. The server receiving this request will decode it back to test|demo automatically.
Incorrect: multiple pipe characters as delimiters
<ahref="https://example.com/filter?colors=red|blue|green">Filter colors</a>
Correct: all pipe characters encoded
<ahref="https://example.com/filter?colors=red%7Cblue%7Cgreen">Filter colors</a>
Generating encoded URLs in JavaScript
If you're building URLs dynamically, use encodeURIComponent() to encode individual parameter values:
<script>
constcolors="red|blue|green";
consturl="https://example.com/filter?colors="+encodeURIComponent(colors);
// Result: "https://example.com/filter?colors=red%7Cblue%7Cgreen"
</script>
This ensures that any special characters in the value — including |, spaces, ampersands, and others — are properly encoded without you needing to remember each character's percent-encoded form.
Other characters to watch for
The pipe character is not the only one that causes this validation error. Other characters that must be percent-encoded in URL query strings include curly braces ({ and }), the caret (^), backtick (`), and square brackets ([ and ]) when used outside of specific contexts. As a general rule, always encode user-supplied or dynamic values using your language's URL encoding function rather than constructing query strings through simple string concatenation.
A space character in the href attribute of an <a> element is not valid in a URL. Spaces must be encoded as %20 in the query string.
URLs follow the syntax defined in RFC 3986, which does not allow literal space characters anywhere in the URL. When the W3C validator encounters a space in a query string, it flags the href value as malformed. Browsers often handle this gracefully by encoding the space automatically, but the HTML itself is still invalid.
The query component of a URL (everything after the ?) follows the same rule. If a value in the query string contains a space, replace each space with %20. An alternative encoding, +, is specific to the application/x-www-form-urlencoded format used by HTML form submissions, and is also accepted in practice by most servers. However, %20 is the universally correct percent-encoding for a space in any part of a URL.
Invalid example
<ahref="https://example.com/search?query=hello world&lang=en">Search</a>
The space between hello and world causes the validation error.
Valid example
<ahref="https://example.com/search?query=hello%20world&lang=en">Search</a>
Every space in the URL is replaced with %20, and the markup passes validation.
The W3C HTML Validator checks that URLs in href attributes conform to the URL standard (defined by WHATWG). While square brackets are permitted in the host component of a URL (to support IPv6 addresses like [::1]), they are not valid unescaped characters in the query string — the part of the URL that comes after the ?. When the validator encounters a literal [ or ] in the query portion, it flags it as an illegal character.
This issue commonly arises when working with APIs or server-side frameworks that use square brackets in query parameters to represent arrays or nested data structures. For example, PHP-style query strings like ?filter[name]=foo or ?ids[]=1&ids[]=2 contain brackets that must be encoded for valid HTML.
Why this matters
- Standards compliance: The WHATWG URL Standard explicitly lists square brackets among the characters that must be percent-encoded in query strings. Invalid URLs cause W3C validation failures.
- Browser behavior: While most modern browsers are forgiving and will often handle unescaped brackets correctly, relying on this lenient parsing is fragile. Some HTTP clients, proxies, or intermediary servers may reject or mangle URLs with illegal characters.
- Interoperability: Encoded URLs are safer when copied, shared, or processed by tools like link checkers, web scrapers, or email clients that may perform strict URL parsing.
How to fix it
Replace every literal square bracket in the query string with its percent-encoded form:
| Character | Percent-encoded |
|---|---|
[ | %5B |
] | %5D |
If you're generating URLs dynamically in a server-side language or JavaScript, use the appropriate encoding function (e.g., encodeURIComponent() in JavaScript, urlencode() in PHP, or urllib.parse.quote() in Python) to handle this automatically.
Examples
Incorrect: literal brackets in the query string
<ahref="https://example.com/search?filter[status]=active">Active items</a>
This triggers the validation error because [ and ] appear unescaped in the query.
Correct: percent-encoded brackets
<ahref="https://example.com/search?filter%5Bstatus%5D=active">Active items</a>
Replacing [ with %5B and ] with %5D resolves the error. The server receiving this request will decode the values back to filter[status]=active.
Incorrect: array-style parameters with brackets
<ahref="/api/items?ids[]=1&ids[]=2&ids[]=3">Load items</a>
Correct: array-style parameters encoded
<ahref="/api/items?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3">Load items</a>
Note that in addition to encoding the brackets, the & characters in HTML attributes should be written as & for fully valid markup.
Incorrect: brackets in a simple value
<ahref="search.html?q=[value]">Search</a>
Correct: encoded brackets in a simple value
<ahref="search.html?q=%5Bvalue%5D">Search</a>
Note on brackets in the host (valid use)
Square brackets are valid in the host portion of a URL for IPv6 addresses. The following does not trigger the error:
<ahref="http://[::1]:8080/page">IPv6 localhost</a>
The validator only flags brackets that appear in the query string or other parts of the URL where they are not permitted.
The W3C HTML Validator raises this error when it encounters a backslash character (\) inside the href attribute of an anchor element. According to the WHATWG URL Standard, backslashes are not valid characters in URL scheme data. URLs are defined with forward slashes (/) as delimiters — this applies to all parts of a URL, including the scheme, authority, path, query, and fragment.
This issue most commonly occurs when developers copy file paths from Windows operating systems, where backslashes are the default path separator (e.g., C:\Users\Documents\file.html), and paste them directly into HTML markup. It can also happen when server-side code generates URLs using OS-level path functions that produce backslashes on Windows.
Why this matters
- Standards compliance: The WHATWG URL Standard explicitly forbids backslashes in scheme data. Validators flag this as an error because the resulting URL is malformed.
- Cross-browser inconsistency: While some browsers may silently correct backslashes to forward slashes, this behavior is not guaranteed across all browsers or versions. Relying on browser error correction leads to fragile code.
- Broken links: Certain browsers, HTTP clients, or intermediary servers may not auto-correct the backslash, causing the link to fail entirely — resulting in 404 errors or unexpected navigation.
- Security concerns: Backslashes in URLs can be exploited in certain attack vectors like open redirects or path traversal attacks. Using well-formed URLs reduces the attack surface.
How to fix it
- Replace all backslashes (
\) with forward slashes (/) in yourhrefvalues. - Check for URL generation in server-side code. If your application builds URLs programmatically, ensure it uses forward slashes regardless of the host operating system.
- Use relative or absolute URLs consistently. Whether the URL is relative (
images/photo.jpg) or absolute (https://example.com/images/photo.jpg), always use forward slashes.
Examples
Incorrect: backslashes in a relative path
<ahref="pages\about\team.html">Meet the Team</a>
Correct: forward slashes in a relative path
<ahref="pages/about/team.html">Meet the Team</a>
Incorrect: backslashes in an absolute URL
<ahref="https://example.com\blog\2024\post.html">Read the Post</a>
Correct: forward slashes in an absolute URL
<ahref="https://example.com/blog/2024/post.html">Read the Post</a>
Incorrect: Windows file path pasted directly
<ahref="assets\downloads\report.pdf">Download Report</a>
Correct: converted to a proper relative URL
<ahref="assets/downloads/report.pdf">Download Report</a>
Incorrect: mixed slashes
Sometimes a URL contains a mix of forward and backslashes, which also triggers this error:
<ahref="https://example.com/images\photos\sunset.jpg">View Photo</a>
Correct: all forward slashes
<ahref="https://example.com/images/photos/sunset.jpg">View Photo</a>
A quick way to audit your HTML files is to search for \ within any href (or src, action, etc.) attribute values and replace them with /. In most code editors, you can use find-and-replace scoped to attribute values to handle this efficiently.
URLs follow strict syntax rules defined by RFC 3986. Within the path segment of a URL, only a specific set of characters is allowed: unreserved characters (letters, digits, -, ., _, ~), percent-encoded characters (like %20), and certain reserved sub-delimiters. When the W3C validator encounters a character outside this allowed set in a <link> element's href attribute, it flags the error.
Common causes of this issue include:
- Template placeholders left in the URL, such as
{{variable}}or${path}, where curly braces and dollar signs haven't been resolved or encoded. - Spaces in file paths, such as
href="styles/my file.css"instead of using%20or renaming the file. - Copy-paste errors that introduce invisible or special Unicode characters.
- Backslashes (
\) used instead of forward slashes (/), which is a common mistake on Windows systems. - Unencoded query-like characters placed in the path portion of the URL.
This matters because browsers may interpret malformed URLs inconsistently. A URL that works in one browser might fail in another. Additionally, invalid URLs can break resource loading, cause accessibility issues when assistive technologies try to process the document, and lead to unexpected behavior with proxies, CDNs, or other intermediaries that strictly parse URLs.
To fix the issue, inspect the href value reported in the error and either:
- Remove the illegal character if it was included by mistake.
- Percent-encode the character if it must be part of the URL (e.g., a space becomes
%20, a pipe|becomes%7C). - Rename the referenced file or directory to avoid special characters altogether (the simplest and most reliable approach).
Examples
Incorrect: Space in the path
<linkrel="stylesheet"href="styles/my styles.css">
The space character is not allowed in a URL path segment. The validator will flag this as an illegal character.
Fixed: Percent-encode the space
<linkrel="stylesheet"href="styles/my%20styles.css">
Better fix: Rename the file to avoid spaces
<linkrel="stylesheet"href="styles/my-styles.css">
Incorrect: Template placeholder left unresolved
<linkrel="stylesheet"href="styles/{{theme}}/main.css">
Curly braces { and } are not valid in URL path segments. This commonly happens with server-side or client-side templating syntax that wasn't processed before the HTML was served.
Fixed: Use a valid resolved path
<linkrel="stylesheet"href="styles/dark/main.css">
Incorrect: Backslash used as path separator
<linkrel="stylesheet"href="styles\main.css">
Backslashes are not valid URL characters. URLs always use forward slashes.
Fixed: Use forward slashes
<linkrel="stylesheet"href="styles/main.css">
Incorrect: Pipe character in the URL
<linkrel="stylesheet"href="styles/font|icon.css">
Fixed: Percent-encode the pipe character
<linkrel="stylesheet"href="styles/font%7Cicon.css">
Full valid document example
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Webpage</title>
<linkrel="stylesheet"href="styles/main.css">
<linkrel="icon"href="images/favicon.ico">
</head>
<body>
<h1>Welcome to my webpage!</h1>
<p>Here is some content.</p>
</body>
</html>
When in doubt, run your URL through a URL encoder or validator separately to confirm all characters are legal. As a general best practice, stick to lowercase letters, digits, hyphens, and forward slashes in your file and directory names—this avoids encoding issues entirely and makes your URLs clean and predictable.
A space character in the href attribute of a <link> element is not valid in a URL and must be encoded as %20.
URLs follow strict syntax rules defined in RFC 3986. Spaces are not permitted anywhere in a URL, including the query string (the part after the ?). When a URL needs to represent a space, it must be percent-encoded as %20.
Browsers are forgiving and will often handle spaces by silently encoding them, but the HTML is still technically invalid. This can lead to unexpected behavior in less forgiving environments like HTML emails, web crawlers, or certain HTTP clients.
Invalid Example
<linkrel="stylesheet"href="https://example.com/styles?family=Open Sans">
Fixed Example
Replace every space with %20:
<linkrel="stylesheet"href="https://example.com/styles?family=Open%20Sans">
If your URL has multiple spaces or special characters, make sure each one is properly percent-encoded. Common replacements include %20 for spaces, %26 for & inside already-encoded contexts, and %3D for =. Most programming languages offer a URL-encoding function (e.g., encodeURI() in JavaScript) to handle this automatically.
A link element's href attribute contains a character that is not valid in a URL, such as a space, curly brace, or other unencoded special character.
URLs in HTML must conform to the URL Living Standard. Certain characters are not allowed to appear literally in a URL and must be percent-encoded. Common offenders include spaces (use %20), curly braces { } (use %7B %7D), pipe | (use %7C), and angle brackets < > (use %3C %3E).
This error often appears when a template placeholder like {{variable}} is left unresolved in the href value, or when a URL is copied from another context and contains unencoded characters. The validator reads the raw HTML source, so even if a browser might handle a malformed URL gracefully, the markup is still invalid.
To fix it, replace every illegal character with its percent-encoded equivalent, or remove the character if it does not belong in the URL.
Examples
Invalid: unencoded characters in href
<linkrel="stylesheet"href="https://example.com/styles/main file.css">
The space between main and file is not allowed in a URL.
Valid: percent-encoded URL
<linkrel="stylesheet"href="https://example.com/styles/main%20file.css">
If the illegal characters come from a template placeholder that was never processed, remove the placeholder or ensure it resolves before the HTML is served:
Invalid: unresolved template syntax
<linkrel="icon"href="https://example.com/{{icon_path}}">
Valid: resolved or corrected URL
<linkrel="icon"href="https://example.com/images/favicon.ico">
The <link> element is used to define relationships between the current document and external resources — most commonly stylesheets, icons, and preloaded assets. The href attribute specifies the URL of that external resource, and it is the core purpose of the element. An empty href attribute makes the <link> element meaningless because there is no resource to fetch or reference.
Why This Is a Problem
Standards compliance: The HTML specification requires the href attribute on <link> to be a valid, non-empty URL. An empty string does not qualify as a valid URL, so the validator flags it as an error.
Unexpected browser behavior: When a browser encounters an empty href, it may resolve it relative to the current document's URL. This means the browser could end up making an unnecessary HTTP request for the current page itself, interpreting the HTML response as a stylesheet or other resource. This wastes bandwidth, can slow down page loading, and may trigger unexpected rendering issues.
Accessibility and semantics: An empty href provides no useful information to browsers, screen readers, or other user agents about the relationship between the document and an external resource. It adds noise to the DOM without contributing anything functional.
How to Fix It
- Provide a valid URL: If the
<link>element is meant to reference a resource, sethrefto the correct URL of that resource. - Remove the element: If no resource is needed, remove the entire
<link>element rather than leaving it with an emptyhref. - Check dynamic rendering: This issue often occurs when a templating engine or CMS outputs a
<link>element with a variable that resolves to an empty string. Add a conditional check so the element is only rendered when a valid URL is available.
Examples
❌ Incorrect: Empty href attribute
<linkrel="stylesheet"href="">
This triggers the validation error because href is empty.
❌ Incorrect: Empty href from a template
<!-- A template variable resolved to an empty string -->
<linkrel="icon"type="image/png"href="">
✅ Correct: Valid href pointing to a resource
<linkrel="stylesheet"href="/css/main.css">
✅ Correct: Valid href for a favicon
<linkrel="icon"type="image/png"href="/images/favicon.png">
✅ Correct: Remove the element if no resource is needed
<!-- Simply omit the <link> element entirely -->
✅ Correct: Conditional rendering in a template
If you're using a templating language, wrap the <link> in a conditional so it only renders when a URL is available. For example, in a Jinja2-style template:
{% if stylesheet_url %}
<linkrel="stylesheet"href="{{ stylesheet_url }}">
{% endif %}
This ensures the <link> element is never output with an empty href.
The id attribute uniquely identifies an element within a document. According to the WHATWG HTML living standard, if the id attribute is specified, its value must be non-empty and must not contain any ASCII whitespace characters. The attribute itself is optional — you don't need to include it — but when you do, it must have a valid value. Setting id="" violates this rule because the empty string is not a valid identifier.
This issue commonly occurs when code is generated dynamically (e.g., by a templating engine or JavaScript framework) and the variable intended to populate the id value resolves to an empty string. It can also happen when developers add the attribute as a placeholder and forget to fill it in.
Why this matters
- Standards compliance: An empty
idviolates the HTML specification, making your document invalid. - Accessibility: Assistive technologies like screen readers rely on
idattributes to associate<label>elements with form controls. An emptyidbreaks this association, making forms harder to use for people who depend on these tools. - JavaScript and CSS: Methods like
document.getElementById("")and selectors like#(with no identifier) will not work as expected. An emptyidcan cause subtle, hard-to-debug issues in your scripts and styles. - Browser behavior: While browsers are generally forgiving, an empty
idleads to undefined behavior. Different browsers may handle it inconsistently.
How to fix it
- Assign a meaningful value: Give the
ida descriptive, unique value that identifies the element's purpose (e.g.,id="country-select"). - Remove the attribute: If you don't need the
id, simply remove it from the element altogether. - Fix dynamic generation: If a templating engine or framework is producing the empty value, add a conditional check to either output a valid
idor omit the attribute entirely.
Examples
❌ Incorrect: empty id attribute
<labelfor="country">Country</label>
<selectid=""name="country">
<optionvalue="us">United States</option>
<optionvalue="ca">Canada</option>
</select>
This triggers the validation error because id="" is an empty string.
✅ Correct: meaningful id value
<labelfor="country">Country</label>
<selectid="country"name="country">
<optionvalue="us">United States</option>
<optionvalue="ca">Canada</option>
</select>
The id now has a valid, non-empty value, and the <label> element's for attribute correctly references it.
✅ Correct: id attribute removed entirely
<label>
Country
<selectname="country">
<optionvalue="us">United States</option>
<optionvalue="ca">Canada</option>
</select>
</label>
If you don't need the id, remove it. Here, the <label> wraps the <select> directly, so the for/id association isn't needed — the implicit label works just as well.
The validator reports “Bad value “” for attribute id on element X: An ID must not be the empty string” when any element includes an empty id attribute. Per the HTML standard, id is a global attribute used as a unique document-wide identifier. An empty identifier is not a valid value and is ignored by some features, leading to hard-to-debug issues.
This matters for accessibility and interoperability. Features that depend on IDs—fragment navigation (#target), <label for>, ARIA attributes like aria-labelledby/aria-controls, and DOM APIs such as document.getElementById()—require a non-empty, unique value. Empty IDs break these links, can degrade assistive technology output, and violate conformance, which may hide bugs across browsers.
How to fix:
- If the element doesn’t need an identifier, remove the
idattribute entirely. - If it needs one, provide a non-empty, unique value, e.g.,
id="main-content". - Ensure uniqueness across the page; each
idmust occur only once. - Use simple, predictable tokens: avoid spaces, prefer lowercase letters, digits, hyphens, and underscores (e.g.,
feature-1). While the spec allows a broad range of characters, sticking to URL- and selector-friendly characters avoids pitfalls.
Examples
Example that triggers the validator error (empty id)
<divid=""></div>
Correct: remove an unnecessary empty id
<div></div>
Correct: provide a meaningful, unique id
<sectionid="features"></section>
Problematic label association with empty id (invalid)
<labelfor="">Email</label>
<inputtype="email"id="">
Correct label–control association
<labelfor="email">Email</label>
<inputtype="email"id="email">
Correct ARIA relationship
<h2id="pricing-heading">Pricing</h2>
<sectionaria-labelledby="pricing-heading">
<p>Choose a plan.</p>
</section>
Correct fragment navigation target
<nav>
<ahref="#contact">Contact</a>
</nav>
<sectionid="contact">
<h2>Contact us</h2>
</section>
Minimal full document (validated) demonstrating proper ids
<!doctype html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>Valid IDs Example</title>
</head>
<body>
<mainid="main-content">
<h1id="page-title">Welcome</h1>
<p>Jump to the <ahref="#details">details</a>.</p>
<sectionid="details">
<h2>Details</h2>
</section>
<form>
<labelfor="email">Email</label>
<inputid="email"type="email">
</form>
</main>
</body>
</html>
The imagesizes attribute is used exclusively on <link> elements that have rel="preload" and as="image". It works in tandem with the imagesrcset attribute to allow the browser to preload the most appropriate image from a set of candidates — mirroring how sizes and srcset work on an <img> element. When the browser encounters these attributes on a <link>, it can begin fetching the right image resource early, before it even parses the <img> tag in the document body.
When imagesizes is set to an empty string (""), the browser has no information about the intended display size of the image, which defeats the purpose of responsive image preloading. The browser cannot select the best candidate from imagesrcset without knowing how large the image will be rendered. An empty value is invalid per the HTML specification, which requires the attribute to contain a valid source size list (the same syntax used by the sizes attribute on <img>).
This matters for both performance and standards compliance. Responsive preloading is a performance optimization — an empty imagesizes undermines that by leaving the browser unable to make an informed choice. From a standards perspective, the validator correctly rejects the empty value because the attribute's defined value space does not include the empty string.
How to fix it
- Provide a valid sizes value that matches the
sizesattribute on the corresponding<img>element in your page. This tells the browser how wide the image will be at various viewport widths. - Remove
imagesizesentirely if you don't need responsive preloading. If you're preloading a single image (usinghrefinstead ofimagesrcset), you don't needimagesizesat all.
Examples
❌ Bad: empty imagesizes attribute
<link
rel="preload"
as="image"
imagesrcset="hero-480.jpg 480w, hero-800.jpg 800w, hero-1200.jpg 1200w"
imagesizes="">
The empty imagesizes="" triggers the validation error and prevents the browser from selecting the correct image candidate.
✅ Fixed: providing a valid sizes value
<link
rel="preload"
as="image"
imagesrcset="hero-480.jpg 480w, hero-800.jpg 800w, hero-1200.jpg 1200w"
imagesizes="(max-width: 600px) 480px, (max-width: 1000px) 800px, 1200px">
The imagesizes value uses the same syntax as the sizes attribute on <img>. It provides media conditions paired with lengths, with a fallback length at the end. This value should match the sizes attribute on the corresponding <img> element in your markup.
✅ Fixed: simple full-width image
<link
rel="preload"
as="image"
imagesrcset="banner-640.jpg 640w, banner-1280.jpg 1280w"
imagesizes="100vw">
If the image spans the full viewport width, 100vw is a straightforward and valid value.
✅ Fixed: removing the attribute when not needed
<linkrel="preload"as="image"href="logo.png">
If you're preloading a single, non-responsive image, omit both imagesrcset and imagesizes and use the href attribute instead. The imagesizes attribute is only meaningful when paired with imagesrcset.
The imagesrcset attribute is used exclusively on <link> elements that have rel="preload" and as="image". It mirrors the srcset attribute of the <img> element, allowing the browser to preload the most appropriate image resource based on the current viewport and display conditions. When the validator encounters imagesrcset="" (an empty value), it reports this error because an empty string is not a valid source set — it must contain at least one image candidate string.
Each image candidate string in the imagesrcset value consists of a URL followed by an optional width descriptor (e.g., 480w) or pixel density descriptor (e.g., 2x). Multiple candidates are separated by commas. This is the same syntax used by the srcset attribute on <img> elements.
This issue typically arises when a CMS, static site generator, or templating engine outputs the imagesrcset attribute with an empty value — for example, when a responsive image field has no data. Browsers may ignore the malformed attribute, but it results in invalid HTML, can cause unexpected preloading behavior, and signals that the page's resource hints are misconfigured. Fixing it ensures standards compliance and that the browser's preload scanner works as intended.
How to fix it
- Provide a valid source set — populate
imagesrcsetwith one or more image candidate strings. - Remove the attribute — if you don't have multiple image sources to preload, remove
imagesrcset(andimagesizes) from the<link>element entirely. You can still preload a single image using just thehrefattribute. - Conditionally render — if your templating system might produce an empty value, add logic to omit the attribute when no responsive sources are available.
When using imagesrcset, you should also include the imagesizes attribute (mirroring the sizes attribute on <img>) so the browser can select the correct candidate based on layout information.
Examples
❌ Empty imagesrcset triggers the error
<linkrel="preload"as="image"href="hero.jpg"imagesrcset=""imagesizes="">
The empty imagesrcset value is invalid and produces the W3C validation error.
✅ Valid imagesrcset with width descriptors
<link
rel="preload"
as="image"
href="hero-800.jpg"
imagesrcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1200.jpg 1200w"
imagesizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px">
This tells the browser to preload the most appropriate image based on the viewport width, matching the responsive behavior of the corresponding <img> element on the page.
✅ Valid imagesrcset with pixel density descriptors
<link
rel="preload"
as="image"
href="logo.png"
imagesrcset="logo.png 1x, logo@2x.png 2x">
This preloads the correct logo variant based on the device's pixel density.
✅ Removing the attribute when no responsive sources exist
<linkrel="preload"as="image"href="hero.jpg">
If you only have a single image to preload, simply use href without imagesrcset. This is valid and avoids the error entirely.
✅ Conditional rendering in a template
If you're using a templating language, conditionally include the attribute:
<!-- Pseudocode example -->
<link
rel="preload"
as="image"
href="hero.jpg"
{%ifresponsive_sources%}
imagesrcset="{{ responsive_sources }}"
imagesizes="{{ image_sizes }}"
{%endif%}>
This prevents the attribute from being rendered with an empty value when no responsive image data is available.
The itemprop attribute cannot be an empty string — it must contain a valid property name when present.
The itemprop attribute is part of the HTML Microdata specification and is used to assign a property name to an element within an itemscope. When a search engine or parser encounters itemprop, it expects a meaningful token that identifies the type of data being described, such as "name", "description", or "url".
If you don't need to mark up the element with microdata, simply remove the itemprop attribute entirely. If you do need it, provide a valid property name that matches the vocabulary you're using (e.g., Schema.org).
HTML Examples
❌ Invalid: empty itemprop
<divitemscopeitemtype="https://schema.org/Product">
<divitemprop="">This causes a validation error</div>
</div>
✅ Fix: provide a valid property name or remove the attribute
<divitemscopeitemtype="https://schema.org/Product">
<divitemprop="description">A great product</div>
</div>
Or, if microdata is not needed:
<div>
<div>No microdata needed here</div>
</div>
The max attribute defines the maximum value that is acceptable and valid for the input containing it. When the browser encounters max="", it expects a valid floating-point number as defined by the HTML specification. An empty string cannot be parsed as a number, so the attribute becomes meaningless and triggers a validation error.
This commonly happens when HTML is generated dynamically by a template engine or framework that outputs an empty value for max when no maximum has been configured. It can also occur when a developer adds the attribute as a placeholder intending to fill it in later.
While most browsers will silently ignore an invalid max value, relying on this behavior is problematic for several reasons:
- Standards compliance: The HTML specification requires
maxto be a valid floating-point number when present. - Predictable validation: An empty
maxmeans no client-side maximum constraint is enforced, which may not be the developer's intent. Explicitly removing the attribute makes that intention clear. - Accessibility: Assistive technologies may read the
maxattribute to communicate input constraints to users. An empty value could lead to confusing or undefined behavior.
This error applies to input types that accept numeric-style max values, including number, range, date, datetime-local, month, week, and time.
How to Fix It
- Set a valid numeric value: If you need a maximum constraint, provide a proper floating-point number (e.g.,
max="100"ormax="99.5"). - Remove the attribute: If no maximum is needed, remove the
maxattribute entirely rather than leaving it empty. - Fix dynamic templates: If your HTML is generated from a template, add a conditional check so that
maxis only rendered when a value is actually available.
Examples
❌ Invalid: Empty max attribute
<labelfor="quantity">Quantity:</label>
<inputtype="number"id="quantity"name="quantity"max="">
The empty string "" is not a valid floating-point number, so this triggers the validation error.
✅ Fixed: Providing a valid numeric value
<labelfor="quantity">Quantity:</label>
<inputtype="number"id="quantity"name="quantity"max="100">
✅ Fixed: Removing the attribute entirely
<labelfor="quantity">Quantity:</label>
<inputtype="number"id="quantity"name="quantity">
If no maximum constraint is needed, simply omit the max attribute.
❌ Invalid: Empty max on a date input
<labelfor="end-date">End date:</label>
<inputtype="date"id="end-date"name="end-date"max="">
✅ Fixed: Valid date value for max
<labelfor="end-date">End date:</label>
<inputtype="date"id="end-date"name="end-date"max="2025-12-31">
For date-related input types, the max value must be in the appropriate date/time format (e.g., YYYY-MM-DD for type="date").
Fixing dynamic templates
If you're generating HTML with a templating language, conditionally include the attribute only when a value exists. For example, in a Jinja2-style template:
<inputtype="number"id="price"name="price"
{%ifmax_price%}max="{{ max_price }}"{%endif%}>
This ensures the max attribute is only rendered when max_price has a valid value, avoiding the empty-string problem entirely.
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
maxlengthattribute to communicate input constraints to users. An empty value could cause confusing or incorrect announcements. - Maintainability: An empty
maxlengthis 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
maxlengthaltogether. 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
<inputtype="text"name="username"maxlength="">
❌ Incorrect: other invalid values
<inputtype="text"name="username"maxlength="-1">
<inputtype="email"name="email"maxlength="none">
<inputtype="text"name="bio"maxlength="10.5">
✅ Correct: explicit maximum length
<inputtype="text"name="username"maxlength="30">
✅ Correct: omit the attribute when no limit is needed
<inputtype="text"name="comment">
✅ Correct: maxlength on a textarea
<textareaname="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 -->
<inputtype="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
maxlengthfor 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
maxlengthmeans 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.
<labelfor="msg">Message</label>
<textareaid="msg"name="message"maxlength=""></textarea>
❌ Invalid: non-numeric maxlength value
Strings, decimals, and negative numbers are also invalid.
<labelfor="bio">Bio</label>
<textareaid="bio"name="bio"maxlength="none"></textarea>
<labelfor="notes">Notes</label>
<textareaid="notes"name="notes"maxlength="-1"></textarea>
✅ Fixed: specific integer value
Set maxlength to the desired character limit.
<labelfor="msg">Message (max 200 characters)</label>
<textareaid="msg"name="message"maxlength="200"></textarea>
✅ Fixed: attribute omitted entirely
If no character limit is needed, simply remove the attribute.
<labelfor="msg">Message</label>
<textareaid="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 %} -->
<labelfor="feedback">Feedback</label>
<textareaid="feedback"name="feedback"maxlength="500"></textarea>
The min attribute defines the minimum acceptable value for form input types such as number, range, date, time, datetime-local, week, and month. When the browser or the W3C validator encounters min="", it attempts to parse the empty string as a floating point number and fails because the empty string is not a valid representation of any number according to the HTML specification's rules for parsing floating point numbers.
This issue commonly arises when templating engines or server-side code dynamically set the min attribute but output an empty value when no minimum is configured, or when developers add the attribute as a placeholder intending to fill it in later.
Why this matters
- Standards compliance: The HTML specification explicitly requires the
minattribute's value to be a valid floating point number (for numeric types) or a valid date/time string (for date/time types). An empty string satisfies neither requirement. - Unpredictable browser behavior: When browsers encounter an invalid
minvalue, they typically ignore the attribute entirely. This means your intended constraint silently disappears, potentially allowing users to submit out-of-range values. - Accessibility concerns: Assistive technologies may rely on
minandmaxto communicate valid input ranges to users. An invalid value can lead to confusing or missing guidance for screen reader users. - Form validation issues: Built-in browser validation using the Constraint Validation API depends on valid
minvalues. An empty string can cause the browser's native validation to behave inconsistently across different browsers.
How to fix it
You have two straightforward options:
- Provide a valid value: Set
minto the actual minimum number or date/time string you want to enforce. - Remove the attribute: If no minimum constraint is needed, simply omit the
minattribute. The input will then accept any value within its type's natural range.
If your min value comes from dynamic server-side or JavaScript logic, make sure the attribute is only rendered when a valid value is available, rather than outputting an empty string as a fallback.
Examples
❌ Invalid: empty string for min
<inputtype="number"min=""max="10">
The empty string "" is not a valid floating point number, so this triggers the validation error.
✅ Fixed: provide a valid number
<inputtype="number"min="0"max="10">
✅ Fixed: remove min if no minimum is needed
<inputtype="number"max="10">
❌ Invalid: empty min on a range input
<inputtype="range"min=""max="100"step="5">
✅ Fixed: valid min on a range input
<inputtype="range"min="0"max="100"step="5">
❌ Invalid: empty min on a date input
<inputtype="date"min=""max="2025-12-31">
For date inputs, min must be a valid date string in YYYY-MM-DD format — an empty string is equally invalid here.
✅ Fixed: valid min on a date input
<inputtype="date"min="2025-01-01"max="2025-12-31">
Handling dynamic values in templates
If you're using a templating language and the minimum value might not always exist, conditionally render the attribute rather than outputting an empty value. For example, in a generic template pseudocode:
<!-- Instead of always outputting the attribute: -->
<inputtype="number"min=""max="10">
<!-- Only include it when a value is available: -->
<inputtype="number"min="5"max="10">
In practice, use your templating engine's conditional logic (e.g., {% if min_value %}min="{{ min_value }}"{% endif %} in Jinja2, or similar constructs) to ensure min is only present when it holds a valid value.
The name attribute on <a> elements was historically used to create named anchors — fragment targets that could be linked to with href="#anchorName". In modern HTML (the WHATWG living standard), the name attribute on <a> is considered obsolete for this purpose. The id attribute is now the standard way to create fragment targets, and it can be placed on any element, not just <a> tags.
Regardless of whether you use name or id, the value must be a non-empty string. The W3C validator enforces this rule because an empty identifier serves no functional purpose — it cannot be referenced by a fragment link, it cannot be targeted by JavaScript, and it creates invalid markup. Browsers may silently ignore it, but it pollutes the DOM and signals a likely mistake in the code.
Empty name attributes often appear in content migrated from older CMS platforms or WYSIWYG editors that inserted placeholder anchors like <a name=""></a>. They can also result from templating systems where a variable intended to populate the attribute resolved to an empty string.
Why this matters
- Standards compliance: Both the WHATWG HTML living standard and the W3C HTML specification require that identifier-like attributes (
id,name) must not be empty strings. - Accessibility: Screen readers and assistive technologies may attempt to process named anchors. Empty identifiers create noise without providing any navigational value.
- Functionality: An empty
nameoridcannot be used as a fragment target, so the element is effectively useless as a link destination.
How to fix it
- Remove the element entirely if the empty anchor serves no purpose — this is the most common fix.
- Replace
namewithidand provide a meaningful, non-empty value if you need a fragment target. - Move the
idto a nearby semantic element instead of using a standalone empty<a>tag. For example, place theiddirectly on a heading, section, or paragraph. - Ensure uniqueness — every
idvalue in a document must be unique.
Examples
❌ Empty name attribute triggers the error
<aname=""></a>
<h2>Introduction</h2>
<p>Welcome to the guide.</p>
❌ Empty name generated by a template
<aname=""></a>
<p>This anchor was meant to be a target but the value is missing.</p>
<ahref="#">Jump to section</a>
✅ Remove the empty anchor if it's unnecessary
<h2>Introduction</h2>
<p>Welcome to the guide.</p>
✅ Use id on the target element directly
<h2id="introduction">Introduction</h2>
<p>Welcome to the guide.</p>
<!-- Link to the section from elsewhere -->
<ahref="#introduction">Go to Introduction</a>
✅ Use id on a standalone anchor if needed
If you need a precise anchor point that doesn't correspond to an existing element, use an <a> tag with a valid, non-empty id:
<aid="section-start"></a>
<p>This paragraph follows the anchor point.</p>
<ahref="#section-start">Jump to section start</a>
✅ Migrate legacy name to id
If your existing code uses the obsolete name attribute with a valid value, update it to use id instead:
<!-- Before (obsolete but was valid in HTML4) -->
<aname="contact"></a>
<!-- After (modern HTML) -->
<aid="contact"></a>
<!-- Even better: put the id on a semantic element -->
<h2id="contact">Contact Us</h2>
The HTML specification requires that if the name attribute is used on a <form> element, its value must be a non-empty string. An empty name="" attribute serves no practical purpose — it doesn't register the form in the document.forms named collection, and it can't be used as a valid reference in scripts. The W3C validator flags this as an error because it violates the content model defined in the WHATWG HTML Living Standard.
The name attribute on a form is primarily used to access the form programmatically through document.forms["formName"]. When the value is empty, this lookup mechanism doesn't work, so the attribute becomes meaningless. This is different from the id attribute, which also identifies elements but participates in fragment navigation and CSS targeting. The name attribute on <form> is specifically for the legacy document.forms named getter interface.
It's worth noting that the name attribute value on a form must not equal an empty string, and it should be unique among the form elements in the forms collection. While duplicate names won't cause a validation error, they can lead to unexpected behavior when accessing forms by name in JavaScript.
How to fix
You have two options:
- Remove the attribute entirely. If you're not referencing the form by name in JavaScript, the
nameattribute is unnecessary. You can useidinstead for CSS or JavaScript targeting. - Provide a meaningful, non-empty value. If you need to reference the form through
document.forms, give it a descriptive name that reflects its purpose.
Examples
❌ Invalid: empty name attribute
<formname="">
<labelfor="email">Email</label>
<inputtype="email"id="email"name="email">
<buttontype="submit">Subscribe</button>
</form>
This triggers the validator error because the name attribute is present but has an empty string value.
✅ Fixed: attribute removed
<form>
<labelfor="email">Email</label>
<inputtype="email"id="email"name="email">
<buttontype="submit">Subscribe</button>
</form>
If you don't need to reference the form by name, simply remove the attribute.
✅ Fixed: meaningful name provided
<formname="subscriptionForm">
<labelfor="email">Email</label>
<inputtype="email"id="email"name="email">
<buttontype="submit">Subscribe</button>
</form>
With a non-empty name, you can now access the form in JavaScript using document.forms["subscriptionForm"] or document.forms.subscriptionForm.
✅ Alternative: using id instead
<formid="subscription-form">
<labelfor="email">Email</label>
<inputtype="email"id="email"name="email">
<buttontype="submit">Subscribe</button>
</form>
In modern development, using id with document.getElementById() or document.querySelector() is often preferred over the name attribute for form identification. The name attribute on <form> is a legacy feature that remains valid but isn't required for most use cases.
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