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 HTML specification requires that the width and height attributes on <img> elements, when present, contain a string representing a non-negative integer — that is, a sequence of one or more ASCII digits like "0", "150", or "1920". An empty string ("") does not satisfy this requirement, so the W3C validator flags it as an error.
This issue commonly arises when:
- A CMS or templating engine outputs width="" or height="" because no dimension value was configured.
- JavaScript dynamically sets img.setAttribute("width", "") instead of removing the attribute.
- A developer adds the attributes as placeholders intending to fill them in later but forgets to do so.
Why it matters
Providing valid width and height attributes is one of the most effective ways to prevent Cumulative Layout Shift (CLS). Browsers use these values to calculate the image’s aspect ratio and reserve the correct amount of space before the image loads. When the values are empty strings, the browser cannot determine the aspect ratio, so no space is reserved — leading to layout shifts as images load in, which hurts both user experience and Core Web Vitals scores.
Beyond performance, invalid attribute values can cause unpredictable rendering behavior across browsers. Some browsers may ignore the attribute, others may interpret the empty string as 0, collapsing the image to zero pixels in that dimension. Standards-compliant HTML also improves accessibility by ensuring assistive technologies can parse the document reliably.
Examples
❌ Invalid: empty string values
<img src="photo.jpg" alt="A sunset over the ocean" width="" height="">
Both width and height are set to empty strings, which is not valid.
✅ Fixed: provide actual dimensions
<img src="photo.jpg" alt="A sunset over the ocean" width="800" height="600">
Replace the empty strings with the image’s actual pixel dimensions. These values should reflect the image’s intrinsic (natural) size. CSS can still be used to scale the image visually — the browser will use the width and height ratio to reserve the correct space.
✅ Fixed: remove the attributes entirely
<img src="photo.jpg" alt="A sunset over the ocean">
If you don’t know the dimensions or prefer to handle sizing purely through CSS, remove the attributes altogether. An absent attribute is valid; an empty one is not.
❌ Invalid: only one attribute is empty
<img src="banner.jpg" alt="Promotional banner" width="1200" height="">
Even if only one attribute has an empty value, the validation error will be triggered for that attribute.
✅ Fixed: both attributes with valid values
<img src="banner.jpg" alt="Promotional banner" width="1200" height="400">
Fixing dynamic/template-generated markup
If a template language is outputting empty attributes, use a conditional to omit them when no value is available. For example, in a template:
<!-- Instead of always outputting the attributes: -->
<img src="photo.jpg" alt="Description" width="" height="">
<!-- Conditionally include them only when values exist: -->
<img src="photo.jpg" alt="Description" width="800" height="600">
If you’re setting dimensions via JavaScript, remove the attribute rather than setting it to an empty string:
// ❌ Don't do this
img.setAttribute("width", "");
// ✅ Do this instead
img.removeAttribute("width");
// ✅ Or set a valid value
img.setAttribute("width", "800");
A note on values
The width and height attributes only accept non-negative integers — whole numbers without units, decimals, or percentage signs. Values like "100px", "50%", or "3.5" are also invalid. Use plain integers like "100" or "600". If you need responsive sizing with percentages or other CSS units, apply those through CSS styles instead.
The xmlns attribute declares the XML namespace for an element. For SVG elements, the only permitted namespace is "http://www.w3.org/2000/svg". When this attribute is present but set to an empty string ("") or any value other than the correct namespace, the W3C validator reports an error because the browser cannot properly associate the element with the SVG specification.
In HTML5 documents (served as text/html), the xmlns attribute on <svg> is actually optional. The HTML parser automatically associates <svg> elements with the correct SVG namespace without needing an explicit declaration. However, if you do include the xmlns attribute — for example, because your SVG was exported from a design tool or copied from an XML-based source — it must contain the exact value "http://www.w3.org/2000/svg". An empty or incorrect value will cause a validation error and could lead to rendering issues in certain contexts.
This matters for several reasons:
- Standards compliance: The HTML specification explicitly restricts the allowed value for xmlns on SVG elements.
- Browser compatibility: While most modern browsers are forgiving in HTML mode, an incorrect namespace can cause problems when SVG content is used in XML contexts (such as XHTML or standalone .svg files).
- Interoperability: Tools and libraries that process your HTML may rely on the correct namespace to identify and manipulate SVG elements.
To fix this issue, you have two options:
- Set the correct value: Replace the empty or incorrect xmlns value with "http://www.w3.org/2000/svg".
- Remove the attribute entirely: Since xmlns is optional in HTML5, simply removing it is often the cleanest solution.
Examples
Incorrect: empty xmlns attribute
This triggers the validation error because the namespace value is an empty string:
<svg xmlns="" width="100" height="100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
Incorrect: wrong namespace value
Any value other than the correct SVG namespace will also trigger this error:
<svg xmlns="http://www.w3.org/2000/html" width="100" height="100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
Fix: use the correct namespace
Set xmlns to the only permitted value:
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
Fix: remove the xmlns attribute
In an HTML5 document, you can omit xmlns altogether since the parser handles the namespace automatically:
<svg width="100" height="100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
Note on inline SVG from external sources
Design tools like Figma, Illustrator, or Inkscape often export SVG files with the xmlns attribute already set correctly. If you’re copying SVG markup and the xmlns value gets accidentally cleared or corrupted during the process, either restore it to "http://www.w3.org/2000/svg" or remove it before embedding the SVG in your HTML. Both approaches will produce valid, working markup.
The W3C HTML specification restricts which ARIA roles can be used on specific elements. An li element already carries the implicit role of listitem when it’s a child of a ul or ol, so adding an explicit role is often unnecessary. The group role, as defined in the WAI-ARIA specification, is meant for container elements that form a logical collection of related items — similar to how a fieldset groups form controls. Applying group to an li element contradicts the element’s purpose as an individual item within a list.
This matters for several reasons. Assistive technologies like screen readers rely on ARIA roles to communicate the structure and purpose of content to users. When an li element is marked with role="group", it overrides the native listitem semantics, potentially confusing users who depend on these tools. A screen reader might announce the element as a group container rather than a list item, breaking the expected navigation pattern of the list. Browsers and assistive technologies are optimized around correct role usage, so invalid combinations can lead to unpredictable behavior.
When you might actually need group
If your intent is to group a set of related elements together, the group role belongs on a wrapping container — not on the individual items inside it. For example, you might use role="group" on a div or a ul that contains a subset of related controls within a larger interface. If an li contains nested interactive content that needs to be grouped, wrap that content in an inner container with the group role instead.
How to fix it
- Remove the role entirely if the li is a standard list item inside a ul or ol. The browser already provides the correct listitem semantics.
- Move the group role to a container element if you genuinely need to create a labeled group of related items.
- Use a different valid role if the li serves a non-standard purpose, such as menuitem, option, tab, treeitem, or presentation, depending on the widget pattern you’re building.
Examples
Incorrect: group role on li elements
<ul>
<li role="group">Fruits</li>
<li role="group">Vegetables</li>
<li role="group">Grains</li>
</ul>
This triggers the validation error because group is not a permitted role for li.
Correct: no explicit role needed
<ul>
<li>Fruits</li>
<li>Vegetables</li>
<li>Grains</li>
</ul>
Each li inside a ul automatically has the listitem role. No additional markup is needed.
Correct: using group on a container element
If you need to group related items with a label, apply the group role to the container:
<div role="group" aria-labelledby="food-heading">
<h2 id="food-heading">Food Categories</h2>
<ul>
<li>Fruits</li>
<li>Vegetables</li>
<li>Grains</li>
</ul>
</div>
Correct: nested groups within list items
If each list item contains a group of related controls, place the group role on an inner wrapper:
<ul>
<li>
<div role="group" aria-label="Text formatting">
<button>Bold</button>
<button>Italic</button>
<button>Underline</button>
</div>
</li>
<li>
<div role="group" aria-label="Text alignment">
<button>Left</button>
<button>Center</button>
<button>Right</button>
</div>
</li>
</ul>
This preserves the list structure while correctly applying the group role to containers of related widgets. The aria-label attribute gives each group an accessible name, which is recommended when using role="group".
A space before the width attribute value is causing the validator to misparse the iframe attributes, likely due to a missing closing quote on the width attribute.
This error typically occurs when there’s a typo in the attribute syntax, such as a missing closing quote or extra spaces inside the attribute value. The validator reads the raw HTML and interprets " height= as part of the width value because the width attribute’s opening quote was never properly closed.
The width and height attributes on an iframe element accept non-negative integer values representing pixels. Each attribute must have its value properly quoted and contain only digits.
HTML Examples
❌ Incorrect
<iframe src="page.html" width="600 height="400"></iframe>
In this example, the closing quote after 600 is missing. The validator sees the width value as 600 height=, which is not a valid number.
✅ Correct
<iframe src="page.html" width="600" height="400"></iframe>
Each attribute has properly matched opening and closing quotes, and the values contain only digits.
The fetchpriority attribute is a hint to the browser about the relative priority of fetching a particular resource compared to other resources of the same type. It is defined in the WHATWG HTML living standard as an enumerated attribute with exactly three valid values:
- high — The resource should be fetched at a higher priority relative to other resources of the same type.
- low — The resource should be fetched at a lower priority relative to other resources of the same type.
- auto — The browser determines the appropriate priority (this is the default behavior).
Values like "highest", "critical", "urgent", or any other string outside these three are not recognized. When the W3C validator encounters an invalid value, it reports: Bad value “highest” for attribute “fetchpriority” on element “link”.
Why This Matters
Standards compliance: Browsers treat unrecognized fetchpriority values as equivalent to "auto", meaning your intended priority hint is silently ignored. If you wrote fetchpriority="highest" expecting it to be even more urgent than "high", that extra emphasis has no effect — the browser simply falls back to its default prioritization.
Developer intent: An invalid value masks your real intention. Another developer reading the code might assume "highest" does something special, when in reality the browser discards it. Using the correct value makes the code’s purpose clear and ensures the hint is actually applied.
Accessibility and performance: The fetchpriority attribute is commonly used on <link rel="preload"> elements for critical resources like fonts, stylesheets, or hero images. If your priority hint is silently ignored due to an invalid value, key resources may not load as quickly as intended, potentially degrading the user experience.
How to Fix It
Replace the invalid value with one of the three accepted values. In most cases, if you used "highest", you likely meant "high":
- Find every <link> element where fetchpriority has an invalid value.
- Change the value to "high", "low", or "auto".
- If you’re unsure which priority to use, omit the attribute entirely — the browser will use "auto" by default.
Note that fetchpriority also works on <img>, <script>, and <iframe> elements, and the same three-value restriction applies to all of them.
Examples
Incorrect: Invalid fetchpriority value
<link rel="preload" href="hero.webp" as="image" fetchpriority="highest">
The value "highest" is not valid. The browser ignores the hint and falls back to default prioritization.
Correct: Using "high" for elevated priority
<link rel="preload" href="hero.webp" as="image" fetchpriority="high">
Correct: Using "low" for deferred resources
<link rel="preload" href="analytics.js" as="script" fetchpriority="low">
Correct: Omitting the attribute for default behavior
<link rel="preload" href="style.css" as="style">
When omitted, the browser uses its default priority logic, which is equivalent to fetchpriority="auto".
Full document example
<!DOCTYPE html>
<html lang="en">
<head>
<title>Fetch Priority Example</title>
<link rel="preload" href="hero.webp" as="image" fetchpriority="high">
<link rel="preload" href="fonts/body.woff2" as="font" type="font/woff2" crossorigin fetchpriority="high">
<link rel="stylesheet" href="style.css">
</head>
<body>
<img src="hero.webp" alt="Hero banner" fetchpriority="high">
<p>Page content goes here.</p>
</body>
</html>
This example preloads a hero image and a font with fetchpriority="high", and also applies the hint to the <img> element itself — all using valid attribute values.
When you set href="http://", the browser and the W3C validator attempt to parse this as an absolute URL. According to the URL Standard, a URL with the http or https scheme must include a non-empty host component. The string http:// has the scheme but nothing after the ://, which makes the host empty and the URL invalid.
This issue typically arises when a URL is dynamically generated but the variable or value for the domain is missing, or when a developer uses http:// as a temporary placeholder during development and forgets to replace it.
Why this matters
- Broken navigation: Clicking a link with href="http://" leads to unpredictable behavior. Some browsers may navigate to an error page, while others may interpret it differently.
- Accessibility: Screen readers announce links to users, including their destinations. An invalid URL creates a confusing experience for assistive technology users who expect the link to go somewhere meaningful.
- Standards compliance: The HTML specification requires that href values be valid URLs. An empty host violates the URL parsing rules, causing the W3C validator to flag it as an error.
- SEO: Search engine crawlers may treat invalid URLs as errors, potentially affecting how your site is indexed.
Examples
❌ Invalid: empty host in URL
<a href="http://">Visit our website</a>
This triggers the error because http:// has no host component.
❌ Invalid: same issue with HTTPS
<a href="https://">Secure link</a>
The https scheme also requires a valid host, so this produces the same error.
✅ Fixed: provide a complete URL
<a href="https://example.com">Visit our website</a>
✅ Fixed: use a fragment placeholder if the URL is unknown
If you need a placeholder link during development, use # instead of an incomplete URL:
<a href="#">Visit our website</a>
✅ Fixed: use a relative URL when linking within the same site
<a href="/about">About us</a>
Handling dynamic URLs
If the href value comes from a template or CMS, make sure the variable outputs a complete URL. For example, if a template produces an empty string, you might end up with:
<!-- If {{ site_url }} is empty, this becomes href="http://" -->
<a href="http://{{ site_url }}">Home</a>
Ensure that the variable always resolves to a valid host, or add a fallback so the link is omitted or replaced with a safe default when the value is missing.
The xmlns attribute declares the XML namespace for the document. When present on the <html> element, the HTML specification requires its value to be exactly http://www.w3.org/1999/xhtml — no variations allowed. The URL http://www.w3.org/1999/html is not a recognized namespace and will be rejected by the validator. This error almost always comes from a typo: the “x” before “html” was accidentally omitted.
Why this matters
While most browsers will still render the page in HTML mode regardless of a malformed xmlns value, an incorrect namespace can cause real problems in certain contexts:
- XHTML processing: If the document is served with an XML content type (e.g., application/xhtml+xml), an invalid namespace will cause XML parsers to reject or misinterpret the document.
- Standards compliance: Validators and automated tools flag this as an error, which can affect quality audits, accessibility checks, and CI/CD pipelines that enforce valid markup.
- Tooling and interoperability: XML-based tools, content management systems, and XSLT transformations rely on correct namespaces to function properly.
How to fix it
You have two options depending on your document type:
- If you need the xmlns attribute (e.g., for XHTML or polyglot documents): Change the value from http://www.w3.org/1999/html to http://www.w3.org/1999/xhtml.
- If you’re writing standard HTML5: Simply remove the xmlns attribute. It’s optional in HTML5 and has no effect when present with the correct value — so omitting it is the cleanest approach.
Examples
Incorrect — misspelled namespace
The value is missing the “x” before “html”:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html" lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Fixed — correct XHTML namespace
Add the missing “x” so the value reads xhtml:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Fixed — standard HTML5 without xmlns
If you don’t need XHTML compatibility, remove the attribute altogether:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
For most modern websites served as text/html, the third option — omitting xmlns entirely — is the simplest and recommended approach. Only include it if your document must also be valid XHTML or will be processed by XML tooling, and always ensure the value is exactly http://www.w3.org/1999/xhtml.
The xmlns attribute declares the XML namespace for a document. The value http://www.w3.org/TR/REC-html40 is a URL that points to the old HTML 4.0 Recommendation specification — it was never a proper XML namespace identifier. It likely ended up in code through confusion between DTD/specification URLs and actual namespace URIs, or by copying markup from outdated templates.
In the HTML5 specification (the WHATWG HTML Living Standard), the xmlns attribute on the <html> element is optional. When present, its value must be exactly http://www.w3.org/1999/xhtml — no other value is permitted. This is true regardless of whether the document is served as text/html or application/xhtml+xml.
Why this matters
- Validation failure: The W3C validator will reject the document because the namespace value is not one of the allowed values.
- Standards compliance: Using an incorrect namespace can cause XML parsers to misinterpret or reject the document, especially when served with an XML content type.
- Legacy confusion: The http://www.w3.org/TR/REC-html40 URL is a specification reference, not a namespace. Namespaces and specification URLs serve fundamentally different purposes in web standards.
How to fix it
The simplest fix for a standard HTML5 document is to remove the xmlns attribute entirely. The HTML parser does not require it, and browsers will process the document correctly without it.
If your document is served as XHTML (application/xhtml+xml), or if you have a specific reason to include the namespace declaration, update the value to the only permitted one: http://www.w3.org/1999/xhtml.
Examples
❌ Incorrect: old HTML 4.0 URL used as namespace
<!DOCTYPE html>
<html xmlns="http://www.w3.org/TR/REC-html40" lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
✅ Fix option 1: remove the xmlns attribute (recommended for HTML5)
For most HTML5 documents served as text/html, simply omit the attribute:
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
✅ Fix option 2: use the correct namespace value
If you need the xmlns attribute (e.g., for XHTML serialization), set it to the only allowed value:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Other incorrect values to watch for
This same error can appear with other invalid namespace URLs. All of the following are wrong:
- http://www.w3.org/TR/REC-html40 (HTML 4.0 spec URL)
- http://www.w3.org/TR/html4/ (another HTML 4 spec URL)
- http://www.w3.org/1999/html (non-existent namespace)
The only valid value is http://www.w3.org/1999/xhtml. When in doubt, remove the xmlns attribute altogether — modern HTML5 documents don’t need it.
Namespace URIs in XML (and by extension in HTML) are identifiers, not actual URLs that a browser fetches. The W3C and WHATWG specifications define http://www.w3.org/1998/Math/MathML as the one and only valid namespace for MathML. Even though http:// and https:// point to the same server in practice, they are different strings — and namespace matching is purely a string comparison. Using https://www.w3.org/1998/Math/MathML creates what the spec considers an entirely different (and unrecognized) namespace.
This is a common mistake because modern best practices encourage using https:// for everything on the web. However, these namespace URIs were standardized long before HTTPS became the norm, and changing them would break backward compatibility across the entire XML ecosystem. The spec is explicit: only http://www.w3.org/1998/Math/MathML is permitted.
How to Fix It
You have two options depending on your document type:
-
HTML5 (recommended): Simply remove the xmlns attribute from the <math> element. The HTML5 parser recognizes <math> and automatically places it in the correct MathML namespace. No explicit declaration is needed.
-
XHTML or XML documents: If you’re serving your document as application/xhtml+xml or working in an XML context where explicit namespaces are required, use the exact URI http://www.w3.org/1998/Math/MathML with http://.
The same rule applies to other well-known namespaces like SVG (http://www.w3.org/2000/svg) and XHTML (http://www.w3.org/1999/xhtml) — always use the http:// form specified in the standard.
Examples
Invalid: using https:// in the namespace URI
The https:// scheme causes the validation error:
<math xmlns="https://www.w3.org/1998/Math/MathML">
<mi>x</mi><mo>+</mo><mn>1</mn>
</math>
Fixed: omit xmlns in HTML5
In an HTML5 document, the parser handles the namespace automatically, so the cleanest fix is to drop xmlns altogether:
<!DOCTYPE html>
<html lang="en">
<head>
<title>MathML Example</title>
</head>
<body>
<math>
<mi>x</mi><mo>+</mo><mn>1</mn>
</math>
</body>
</html>
Fixed: use the correct http:// URI
If you need to explicitly declare the namespace (for example, in XHTML served as XML), use the exact http:// URI:
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mi>x</mi><mo>+</mo><mn>1</mn>
</math>
Quick comparison
| Code | Valid? |
|---|---|
| <math xmlns="https://www.w3.org/1998/Math/MathML"> | ❌ Wrong scheme |
| <math xmlns="http://www.w3.org/1998/Math/MathML"> | ✅ Correct URI |
| <math> (in HTML5) | ✅ Namespace implied |
XML namespaces are identified by URI strings that act as unique names. They are never fetched or loaded by the browser — they simply serve as an identifier that must match exactly what the specification defines. The XLink namespace has been defined as http://www.w3.org/1999/xlink since its inception, and changing the protocol to https creates a completely different string that parsers and validators do not recognize.
It’s a common and understandable mistake. Developers are trained to prefer https:// URLs everywhere for security, and many linting tools or habits may encourage automatically converting http:// to https://. However, namespace URIs are a special case where this rule does not apply. The string is purely declarative — no network request is made, and no security benefit comes from using https.
It’s also worth noting that the xmlns:xlink attribute is largely obsolete in modern HTML. When SVG is embedded directly in an HTML5 document, browsers automatically handle namespace resolution. You only need xmlns:xlink when serving SVG as standalone XML (with an .svg file or application/xhtml+xml content type). In most cases, you can simply remove the attribute altogether and use xlink:href or, even better, the plain href attribute, which is now supported on SVG elements like <use>, <image>, and <a>.
Examples
Incorrect: using https:// in the namespace URI
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="https://www.w3.org/1999/xlink">
<use xlink:href="#icon-star"></use>
</svg>
This triggers the validation error because https://www.w3.org/1999/xlink does not match the required namespace identifier.
Fixed: using the correct http:// namespace URI
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<use xlink:href="#icon-star"></use>
</svg>
Preferred: removing the namespace and using plain href
In HTML5, you can drop the xmlns:xlink declaration entirely and use the standard href attribute instead of xlink:href:
<svg xmlns="http://www.w3.org/2000/svg">
<use href="#icon-star"></use>
</svg>
This is the cleanest approach for inline SVG in modern HTML documents. The xlink:href attribute is deprecated in SVG 2, and all modern browsers support plain href on SVG linking elements.
An XML namespace URI is a unique identifier, not an actual web address that your browser fetches. The SVG namespace was defined as http://www.w3.org/2000/svg in the original SVG specification, and that exact string is what HTML parsers and validators expect. Even though using https everywhere is a best practice for real network requests, namespace URIs are not network requests — they are simply fixed strings used to identify which XML vocabulary an element belongs to.
When you write https://www.w3.org/2000/svg instead of http://www.w3.org/2000/svg, the validator sees an unrecognized namespace. This can also cause problems in certain XML-based contexts (such as XHTML or standalone SVG files), where the browser may fail to recognize the element as SVG at all, resulting in your graphics not rendering. In standard HTML5 mode, most browsers will still render inline SVGs correctly regardless of the xmlns value, but the markup is technically invalid and may cause issues in stricter parsing environments like XML serializers, server-side renderers, or tools that process SVG as XML.
This mistake is especially common because many developers reflexively change http to https — or their editor or linter automatically does — when they see a URL-like string. The same principle applies to other namespace URIs like http://www.w3.org/1999/xhtml for HTML and http://www.w3.org/1998/Math/MathML for MathML. These are all fixed identifiers that must not be altered.
How to Fix It
Replace https:// with http:// in the xmlns attribute value. That’s it — no other changes are needed.
If your project uses automated tooling that rewrites http URLs to https, you may need to configure an exception for XML namespace URIs.
Examples
❌ Incorrect: Using https in the namespace URI
<svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="blue" />
</svg>
This triggers the validation error because https://www.w3.org/2000/svg is not a recognized namespace value.
✅ Correct: Using http in the namespace URI
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="blue" />
</svg>
✅ Correct: Inline SVG in HTML without xmlns
When embedding SVG directly inside an HTML5 document, the xmlns attribute is optional — the HTML parser automatically assigns the correct namespace to <svg> elements:
<svg viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="blue" />
</svg>
This is perfectly valid HTML5. You only need the xmlns attribute when the SVG is served as a standalone .svg file or used within an XHTML document.
The WAI-ARIA specification defines a specific set of role values that assistive technologies like screen readers understand. These include roles such as button, checkbox, alert, dialog, img, navigation, banner, and many others. The value "icon" is not among them. When a browser or assistive technology encounters an unrecognized role, it cannot determine the element’s purpose, which defeats the goal of using ARIA in the first place.
This is primarily an accessibility problem. Screen readers rely on valid ARIA roles to communicate the nature of elements to users. An invalid role like "icon" is either ignored or causes unpredictable behavior, leaving users of assistive technologies without the context they need. It’s also a standards compliance issue — the W3C validator flags this because the HTML specification requires role values to match roles defined in the ARIA specification.
The fix depends on the purpose of the element:
- Decorative icons (that don’t convey information): Remove the role attribute entirely, or use aria-hidden="true" to explicitly hide the element from the accessibility tree.
- Meaningful icons (that convey information visually): Use role="img" along with an aria-label to provide a text alternative.
- Icons inside interactive elements: Hide the icon with aria-hidden="true" and ensure the parent interactive element has an accessible name through visible text or an aria-label.
Examples
❌ Invalid: Using the non-existent "icon" role
<span class="icon" role="icon"></span>
This triggers the validation error because "icon" is not a valid ARIA role.
✅ Fixed: Decorative icon with no role
If the icon is purely decorative and doesn’t convey any meaning (e.g., it’s next to text that already describes the action), simply remove the role attribute. Adding aria-hidden="true" ensures screen readers skip over it completely.
<span class="icon" aria-hidden="true"></span>
✅ Fixed: Meaningful icon using role="img"
If the icon conveys meaningful information that isn’t available through surrounding text, use role="img" and provide a descriptive aria-label:
<span class="icon-warning" role="img" aria-label="Warning"></span>
This tells assistive technologies that the element represents an image and gives it an accessible name of “Warning.”
✅ Fixed: Icon inside a button
When an icon is placed inside an interactive element like a button, hide the icon from the accessibility tree and let the button’s text or label provide the meaning:
<button>
<span class="icon-save" aria-hidden="true"></span>
Save
</button>
If the button has no visible text (an icon-only button), provide an aria-label on the button itself:
<button aria-label="Save">
<span class="icon-save" aria-hidden="true"></span>
</button>
✅ Fixed: Icon using an <img> element instead
If you’re using an actual image file for the icon, consider using a semantic <img> element, which has a built-in img role:
<img src="icon-alert.svg" alt="Alert" class="icon">
For decorative image icons, use an empty alt attribute:
<img src="icon-decorative.svg" alt="" class="icon">
The type attribute on a <link> element must contain a single MIME type, not a comma-separated list of multiple types.
The type attribute specifies the MIME type of the linked resource and only accepts one value. It helps the browser decide whether it can handle the resource before downloading it. If you want to reference a favicon that could be in PNG or ICO format, you should pick the single correct MIME type that matches the actual file you’re linking to.
For .png favicons, use image/png. For .ico favicons, use image/x-icon. If you need to support both formats, use separate <link> elements — one for each file.
Invalid Example
<link rel="icon" type="image/png, image/x-icon" href="/favicon.png">
Valid Examples
If your favicon is a PNG file:
<link rel="icon" type="image/png" href="/favicon.png">
If you want to provide both formats, use two separate <link> elements:
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
The browser will select the most appropriate icon from the available options. Most modern browsers prefer PNG, while older browsers will fall back to ICO.
The section element carries implicit ARIA semantics — it maps to role="region" when given an accessible name. According to the ARIA in HTML specification, each HTML element has a set of roles it is allowed to assume, and list is not among the permitted roles for section. When the W3C validator encounters role="list" on a section, it flags this as a bad value because the role conflicts with the element’s intended purpose as a sectioning landmark.
This matters for several reasons. First, assistive technologies like screen readers rely on the correct pairing of elements and roles to convey page structure. A section announced as a list creates a confusing, contradictory experience — the underlying DOM says “this is a document section” while the ARIA role says “this is a list.” Second, browsers may handle conflicting semantics unpredictably, leading to inconsistent behavior across platforms. Third, the HTML specification explicitly defines which roles are valid on each element, and violating these rules means your markup is non-conforming.
The best fix is almost always to use native HTML list elements. The ul, ol, and li elements provide built-in list semantics that all browsers and assistive technologies understand without any extra ARIA attributes. Native elements also handle keyboard interaction and focus management correctly out of the box.
If your design requires a custom component where native list markup isn’t feasible — for example, a complex card grid that functions as a list — you can apply role="list" to a semantically neutral element like div or span. Each direct child acting as a list item should then receive role="listitem". This approach satisfies the ARIA specification while avoiding the element-role conflict.
If you actually need a section to group content within a page region and the list is just part of that section, nest a proper list inside the section rather than trying to make the section itself behave as a list.
Examples
❌ Bad: role="list" on a section element
This triggers the validation error because list is not an allowed role for section.
<section role="list">
<div>Item A</div>
<div>Item B</div>
</section>
✅ Fixed: Use native list elements (recommended)
Native lists provide the best accessibility support with no ARIA needed.
<ul>
<li>Item A</li>
<li>Item B</li>
</ul>
✅ Fixed: Nest a list inside the section
If you need the sectioning semantics of section alongside a list, nest the list inside it.
<section aria-labelledby="resources-heading">
<h2 id="resources-heading">Resources</h2>
<ul>
<li>Item A</li>
<li>Item B</li>
</ul>
</section>
✅ Fixed: ARIA roles on a neutral container
Use this only when native list markup is not possible, such as for highly custom UI components.
<div role="list">
<div role="listitem">Item A</div>
<div role="listitem">Item B</div>
</div>
✅ Fixed: Remove the role entirely
If the content isn’t actually a list, simply remove the role attribute and let the section carry its natural semantics.
<section>
<h2>Updates</h2>
<div>Item A</div>
<div>Item B</div>
</section>
The article element is a sectioning content element that represents a self-contained composition — a blog post, a news story, a forum entry, or similar independent content. Because it carries the implicit ARIA role of article, it functions as a landmark that assistive technologies recognize and expose to users for navigation. Overriding this landmark role with listitem creates a conflict: the element loses its article semantics for assistive technology users, and the listitem role itself becomes invalid because ARIA’s role mapping rules don’t permit it on article.
According to the ARIA in HTML specification, each HTML element has a set of allowed ARIA roles. The article element only permits a narrow set of roles (such as application, document, feed, main, none, presentation, and region). The listitem role is not among them. This restriction exists to prevent authors from creating confusing or contradictory semantics that would degrade the accessibility experience.
Beyond validation, this matters for real users. Screen readers rely on role information to convey structure. An article announced as a listitem is misleading — the user loses the ability to navigate by article landmarks, and the listitem may not function correctly without a proper parent list context. Browsers and assistive technologies expect listitem roles to appear as direct children of an element with role="list" (or within native ul/ol elements).
How to fix it
The solution depends on your intent:
- If you want a list of articles, use native HTML list markup (ul or ol with li) and place each article inside a list item. This gives you both list semantics and article landmarks without any ARIA overrides.
- If you can’t use native list elements, use neutral div elements with role="list" and role="listitem", and nest the article inside each listitem container.
- If the content isn’t truly a list, simply remove the role="listitem" attribute and let the article element use its native semantics.
Examples
Invalid: role="listitem" on an article element
This triggers the validator error because listitem is not an allowed role for article.
<article role="listitem">
<h2>News item</h2>
<p>Details about this story.</p>
</article>
Valid: native list with article elements inside
Using ul and li provides proper list semantics while preserving the article landmark role.
<ul>
<li>
<article>
<h2>News item</h2>
<p>Details about this story.</p>
</article>
</li>
<li>
<article>
<h2>Another item</h2>
<p>More details here.</p>
</article>
</li>
</ul>
Valid: ARIA list roles on neutral containers with nested article elements
When native list elements aren’t suitable for your layout, use div elements for the list structure and nest each article inside.
<div role="list">
<div role="listitem">
<article>
<h2>News item</h2>
<p>Details about this story.</p>
</article>
</div>
<div role="listitem">
<article>
<h2>Another item</h2>
<p>More details here.</p>
</article>
</div>
</div>
Valid: standalone article without a list role
If the content doesn’t belong in a list, simply remove the invalid role.
<article>
<h2>News item</h2>
<p>Details about this story.</p>
</article>
In every case, the key principle is the same: let the article element keep its native semantics, and use the appropriate list structure around it rather than forcing a conflicting role onto it.
A mailto: link follows URI syntax as defined by RFC 3986, which does not permit raw space characters anywhere in the URI. When the W3C validator encounters a space inside the href value of a mailto: link, it reports it as an illegal character in the scheme data. This most commonly happens due to a typo in the email address itself — for example, accidentally inserting a space in the domain name (example .com) or the local part (user name@example.com). It can also occur when query parameters like subject or body contain unencoded spaces.
This matters for several reasons. First, browsers may truncate or misinterpret the href at the space boundary, meaning the mail client may open with an incorrect or incomplete email address. Second, assistive technologies rely on well-formed URIs to communicate link destinations to users. A malformed mailto: link can confuse screen readers or prevent users from understanding where the link leads. Third, invalid markup signals poor quality to search engines and automated tools.
To fix this issue:
- Check the email address for typos. Remove any accidental spaces in the local part (before @) or the domain part (after @).
- Percent-encode spaces in query parameters. If you’re using subject, body, or cc parameters in the mailto: URI, replace spaces with %20.
- Avoid copying and pasting email addresses from formatted documents, which can introduce non-breaking spaces or other invisible whitespace characters.
Examples
Invalid — space in the email address
A space in the domain name makes the URI invalid:
<a href="mailto:user@example com">Send Email</a>
Valid — corrected email address
Remove the space to form a valid email address:
<a href="mailto:user@example.com">Send Email</a>
Invalid — space in the local part
<a href="mailto:john doe@example.com">Send Email</a>
Valid — space removed from local part
<a href="mailto:johndoe@example.com">Send Email</a>
Invalid — unencoded spaces in subject parameter
<a href="mailto:info@example.com?subject=Hello World">Email Us</a>
Valid — percent-encoded spaces in subject parameter
Replace each space with %20 in query parameter values:
<a href="mailto:info@example.com?subject=Hello%20World">Email Us</a>
Valid — full mailto with multiple parameters
<a href="mailto:support@example.com?subject=Bug%20Report&body=Please%20describe%20the%20issue.">
Report a Bug
</a>
In HTML, every element has a set of ARIA roles it is allowed to carry. The ul element implicitly has the list role, and the ARIA specification only permits certain roles to override it — specifically directory, group, listbox, menu, menubar, none, presentation, radiogroup, tablist, toolbar, and tree. The navigation role is not among them.
The navigation role is a landmark role, meaning it identifies a major section of the page dedicated to navigational links. HTML5 introduced the nav element specifically for this purpose, and it carries the navigation role implicitly — no role attribute needed. When you place role="navigation" on a ul, you’re conflicting with the element’s semantics. A ul represents a list of items, not a navigational landmark. Assistive technologies like screen readers rely on correct role assignments to help users understand page structure and navigate efficiently. An incorrect role can confuse users by misrepresenting what the element actually is.
Beyond accessibility concerns, this is a standards compliance issue. The W3C validator enforces the rules defined in the ARIA in HTML specification, which maps each HTML element to its allowed roles. Violating these rules means your markup is invalid and may behave unpredictably across different browsers and assistive technologies.
The fix is straightforward: use a nav element as the wrapper for your navigation list. This gives you the navigation landmark semantics automatically, while the ul retains its proper list role. Both elements work together — the nav tells assistive technologies “this is a navigation section,” and the ul tells them “here is a list of links.”
Examples
❌ Incorrect: navigation role on a ul
This triggers the validation error because navigation is not an allowed role for ul.
<ul role="navigation">
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
✅ Correct: wrapping the ul in a nav element
The nav element provides the navigation landmark implicitly. No role attribute is needed.
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
✅ Correct: labeling multiple navigation landmarks
When a page has more than one nav element, use aria-label to distinguish them for screen reader users.
<nav aria-label="Main">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
<nav aria-label="Footer">
<ul>
<li><a href="/privacy">Privacy Policy</a></li>
<li><a href="/terms">Terms of Service</a></li>
</ul>
</nav>
✅ Correct: using an allowed role on ul
If you need the ul to behave as something other than a plain list — for example, a menu in a web application — use one of its permitted roles.
<ul role="menubar">
<li role="menuitem"><a href="/">Home</a></li>
<li role="menuitem"><a href="/about">About</a></li>
<li role="menuitem"><a href="/contact">Contact</a></li>
</ul>
Note that menu and menubar roles are meant for application-style menus with keyboard interaction, not for simple site navigation. For standard website navigation, the nav wrapper approach is almost always the right choice.
The autocomplete="new-password" value can only be used on <input> elements whose type accepts password input, specifically type="password".
The autocomplete attribute helps browsers autofill form fields. However, certain autofill tokens are restricted to specific input types. The new-password token tells the browser to suggest a new, generated password — which only makes sense on a password field. If you use it on a type="text", type="email", or other non-password input, the validator will flag it as invalid.
The same restriction applies to current-password. Both tokens are exclusively valid on <input type="password">.
Invalid Example
<label for="pass">Create a password</label>
<input type="text" id="pass" autocomplete="new-password">
Valid Example
<label for="pass">Create a password</label>
<input type="password" id="pass" autocomplete="new-password">
If your field is not meant to collect a password, use a different autocomplete value appropriate for the input type, such as username, email, or off.
The autocomplete attribute tells the browser how to handle autofilling a form field. The HTML specification defines a strict set of allowed values: the keywords on and off, and a collection of autofill field names such as name, email, username, new-password, street-address, and many others. The value "none" is not part of this specification, even though it might seem like a logical choice for “no autocomplete.”
This confusion likely arises because some non-web APIs and frameworks use "none" as a keyword to disable features. In HTML, however, the correct keyword to disable autocompletion is "off". Using an invalid value like "none" leads to undefined browser behavior — some browsers may ignore it entirely and autofill anyway, while others might treat it as equivalent to "on". This inconsistency can cause unexpected user experiences and potential security concerns, especially for sensitive fields like passwords or credit card numbers.
Beyond standards compliance, using valid autocomplete values improves accessibility. Assistive technologies and password managers rely on recognized autofill field names to help users fill out forms efficiently. When a valid, descriptive value like "username" or "email" is provided, browsers and assistive tools can offer more accurate suggestions.
How to fix it
Replace "none" with the appropriate valid value:
- Use "off" if you want to disable autofill for the field.
- Use "on" if you want the browser to decide how to autofill the field.
- Use a specific autofill field name if you want to hint at the type of data expected.
Common autofill field names include: name, given-name, family-name, email, username, new-password, current-password, tel, street-address, postal-code, country, cc-number, cc-exp, and cc-name. You can also combine tokens, such as "shipping postal-code" or "billing cc-number", to provide additional context through section and hint tokens.
Note: Even with autocomplete="off", some browsers may still autofill certain fields (particularly login credentials) for security or usability reasons. This is browser-specific behavior and not something the HTML specification can override.
Examples
Incorrect: using "none" to disable autofill
<form>
<label for="user">Username</label>
<input type="text" id="user" name="username" autocomplete="none">
</form>
Correct: using "off" to disable autofill
<form>
<label for="user">Username</label>
<input type="text" id="user" name="username" autocomplete="off">
</form>
Correct: using a specific autofill field name
When you know what kind of data a field collects, providing a descriptive autofill field name is often better than using "on" or "off". This helps browsers offer accurate suggestions:
<form>
<label for="user">Username</label>
<input type="text" id="user" name="username" autocomplete="username">
<label for="email">Email</label>
<input type="email" id="email" name="email" autocomplete="email">
<label for="pwd">New Password</label>
<input type="password" id="pwd" name="password" autocomplete="new-password">
</form>
Correct: using section and hint tokens
You can prefix an autofill field name with a section name or shipping/billing hint to distinguish between multiple addresses in the same form:
<form>
<label for="ship-zip">Shipping postal code</label>
<input type="text" id="ship-zip" name="ship_zip" autocomplete="shipping postal-code">
<label for="bill-zip">Billing postal code</label>
<input type="text" id="bill-zip" name="bill_zip" autocomplete="billing postal-code">
</form>
The SVG font-weight presentation attribute controls the boldness or lightness of glyphs used to render text. According to the SVG specification, this attribute is only valid on text content elements: <text>, <tspan>, <textPath>, and the deprecated <tref>. While the <g> element is a general-purpose container for grouping SVG elements, it does not accept font-weight as a direct attribute in valid markup.
The value "none" compounds the problem because it is not a recognized value for font-weight in any context. The allowed values are:
- normal (equivalent to 400)
- bold (equivalent to 700)
- bolder (relative to parent)
- lighter (relative to parent)
- A numeric value: 100, 200, 300, 400, 500, 600, 700, 800, or 900
This matters for standards compliance and predictable rendering across browsers. While some browsers may silently ignore invalid attributes or values, relying on that behavior leads to fragile code. Using valid attributes on the correct elements ensures consistent results and avoids validation errors.
If you need to apply a font-weight to multiple text elements inside a <g>, use CSS instead. You can apply a style via the style attribute on the <g>, a class, or an inline <style> block. CSS font-weight is inherited, so child text elements will pick it up.
Examples
Invalid: font-weight="none" on a <g> element
<svg viewBox="0 0 200 30" xmlns="http://www.w3.org/2000/svg">
<g font-weight="none">
<text y="20">Hello</text>
</g>
</svg>
This triggers the validation error because <g> does not accept the font-weight attribute directly, and "none" is not a valid value.
Fixed: font-weight on the <text> element with a valid value
<svg viewBox="0 0 200 30" xmlns="http://www.w3.org/2000/svg">
<g>
<text y="20" font-weight="bold">Hello</text>
</g>
</svg>
Fixed: using a numeric weight on <text>
<svg viewBox="0 0 200 30" xmlns="http://www.w3.org/2000/svg">
<text y="20" font-weight="700">Bold text</text>
<text x="100" y="20" font-weight="400">Normal text</text>
</svg>
Fixed: applying font-weight to a <g> via CSS
If you want all text inside a <g> to share the same weight, use the style attribute or a CSS class. CSS-based font-weight on a <g> is valid because CSS inheritance applies to all descendant text content.
<svg viewBox="0 0 300 30" xmlns="http://www.w3.org/2000/svg">
<g style="font-weight: bold">
<text y="20">This is bold</text>
<text x="150" y="20">Also bold</text>
</g>
</svg>
Fixed: using an inline <style> block
<svg viewBox="0 0 300 30" xmlns="http://www.w3.org/2000/svg">
<style>
.heavy { font-weight: 900; }
</style>
<g class="heavy">
<text y="20">Heavy text</text>
<text x="150" y="20">Also heavy</text>
</g>
</svg>
This W3C validation error has two distinct problems combined into one message. First, the value "none" is not a recognized value for the text-anchor attribute — the only accepted values are start, middle, and end. Second, the <g> element is a generic container used to group SVG shapes together and does not support the text-anchor attribute directly.
The text-anchor attribute controls how text is aligned relative to its anchor point (the x coordinate). A value of start aligns the beginning of the text to the anchor, middle centers the text on the anchor, and end aligns the end of the text to the anchor. There is no "none" value because text always needs an alignment — start is the default if the attribute is omitted.
Why this is a problem
- Invalid markup: Using an unrecognized value like "none" means browsers must guess the intended behavior, which can lead to inconsistent rendering across different environments.
- Wrong element: The <g> element does not directly render text, so text-anchor has no meaningful effect on it. While CSS inheritance might cause child text elements to pick up styles from a parent <g>, the text-anchor presentation attribute is only valid on elements that actually render text content.
- Standards compliance: The SVG specification explicitly defines which elements accept text-anchor and which values are allowed. Violating this produces validation errors and may cause issues with SVG processing tools.
How to fix it
- Remove the attribute from the <g> element and apply it to the appropriate text element inside the group.
- Replace "none" with a valid value: start, middle, or end. If you want the default behavior (left-aligned for LTR text), simply omit the attribute entirely, as start is the default.
- If you need to set text-anchor for multiple text elements inside a group, use CSS instead of the presentation attribute.
Examples
❌ Invalid: "none" on a <g> element
<svg width="200" height="200">
<g text-anchor="none">
<text x="100" y="100">Hello</text>
</g>
</svg>
✅ Fixed: valid value on the <text> element
<svg width="200" height="200">
<text x="100" y="100" text-anchor="middle">Hello</text>
</svg>
✅ Fixed: attribute removed entirely (uses default start)
<svg width="200" height="200">
<g>
<text x="100" y="100">Hello</text>
</g>
</svg>
✅ Using CSS to style text inside a group
If you want all text elements within a group to share the same alignment, apply the style via CSS rather than a presentation attribute on <g>:
<svg width="200" height="200">
<style>
.centered-text text {
text-anchor: middle;
}
</style>
<g class="centered-text">
<text x="100" y="50">First line</text>
<text x="100" y="100">Second line</text>
</g>
</svg>
✅ Valid use on other text-related elements
The text-anchor attribute can also be applied to <tspan> and <textPath>:
<svg width="300" height="100">
<text x="150" y="50" text-anchor="start">
Start-aligned
<tspan x="150" dy="30" text-anchor="end">End-aligned span</tspan>
</text>
</svg>
The autocomplete attribute on <form> elements controls whether the browser should automatically fill in form fields based on previously entered data. Unlike autocomplete on <input> elements — which accepts a rich set of tokens like "name", "email", "street-address", etc. — the <form> element itself only accepts two values: "on" and "off".
A common workaround that gained popularity was setting autocomplete="nope" (or other made-up values like "new-password", "false", or "disabled") on the <form> element. This hack exploited the fact that some browsers would treat any unrecognized value as a signal to disable autocomplete. However, this behavior is non-standard and unreliable — browsers may ignore invalid values entirely and fall back to their default behavior, which is typically "on".
Using invalid attribute values causes several problems:
- Standards compliance: The HTML specification explicitly defines the allowed values, and validators will flag anything else as an error.
- Unpredictable behavior: Different browsers handle invalid values differently. What works in one browser today may stop working in the next update.
- Accessibility and user experience: Assistive technologies and browser features rely on standard attribute values to function correctly. Invalid values can interfere with password managers and autofill tools that many users depend on.
It’s worth noting that even with autocomplete="off", some browsers (particularly Chrome) may still autofill certain fields like login credentials for security reasons. If you need finer-grained control, apply autocomplete attributes directly on individual <input> elements using the appropriate autofill tokens from the specification.
Examples
❌ Invalid: Using a made-up value on a form
<form autocomplete="nope" action="/submit" method="post">
<label for="username">Username</label>
<input type="text" id="username" name="username">
<button type="submit">Submit</button>
</form>
This triggers the error Bad value “nope” for attribute “autocomplete” on element “form” because "nope" is not a valid autocomplete value for <form>.
✅ Fixed: Using the correct value to disable autocomplete
<form autocomplete="off" action="/submit" method="post">
<label for="username">Username</label>
<input type="text" id="username" name="username">
<button type="submit">Submit</button>
</form>
✅ Using autocomplete on individual inputs for more control
If you need to disable autocomplete for specific fields while leaving others enabled, apply the attribute directly on the <input> elements instead:
<form action="/submit" method="post">
<label for="username">Username</label>
<input type="text" id="username" name="username" autocomplete="username">
<label for="secret">One-time code</label>
<input type="text" id="secret" name="secret" autocomplete="off">
<button type="submit">Submit</button>
</form>
In this example, the username field uses the standard "username" autofill token to help browsers fill it correctly, while the one-time code field has autocomplete disabled since its value should never be reused.
The autocomplete attribute tells the browser how to handle autofill for a form field. The HTML specification defines a strict set of valid values, which include "on", "off", and a list of autofill field names such as "username", "new-password", "cc-number", "postal-code", and many others. When you use a value that isn’t in this list — such as "nope", "false", "none", or any other made-up string — the W3C validator reports it as an invalid autofill field name.
A common reason developers use values like "nope" is as a workaround because some browsers historically ignored autocomplete="off". In older versions of Chrome and Firefox, the browser would still show autofill suggestions even when off was set, so developers discovered that using an unrecognized value like "nope" effectively tricked the browser into not showing suggestions. While this hack may have worked in practice, it produces invalid HTML and is not a reliable long-term solution since browser behavior around unrecognized values can change at any time.
Why this matters
- Standards compliance: Invalid attribute values make your HTML non-conforming, which can cause issues with tooling, testing pipelines, and accessibility auditors.
- Accessibility: Screen readers and assistive technologies rely on valid autocomplete values to help users fill in forms. Using a correct autofill field name like "given-name" or "email" can significantly improve the experience for users with disabilities. In fact, WCAG 2.1 Success Criterion 1.3.5 specifically recommends using valid autocomplete values for fields that collect user information.
- Browser behavior: Modern browsers have improved their handling of autocomplete="off". Using the standard value is now more reliable than it once was, and using it correctly ensures predictable behavior across browsers.
How to fix it
- To disable autocomplete, replace the invalid value with "off".
- To enable smart autofill, use the appropriate autofill field name from the HTML specification’s list of autofill field names. This is the preferred approach for most user-facing forms.
- For new passwords (e.g., registration or password-change forms), use "new-password" — this tells the browser to suggest a generated password rather than filling in a saved one.
Examples
Invalid: made-up autocomplete value
<input type="text" name="firstName" autocomplete="nope">
Other common invalid values that trigger the same error include "false", "none", "disable", and "no".
Fixed: disabling autocomplete with "off"
<input type="text" name="firstName" autocomplete="off">
Fixed: using a valid autofill field name
Using a specific autofill field name is often better than "off" because it helps browsers and assistive technologies understand the purpose of the field:
<input type="text" name="firstName" autocomplete="given-name">
Fixed: common valid autocomplete values in a form
<form method="post" action="/register">
<label for="name">Full Name</label>
<input type="text" id="name" name="name" autocomplete="name">
<label for="email">Email</label>
<input type="email" id="email" name="email" autocomplete="email">
<label for="newpass">Password</label>
<input type="password" id="newpass" name="password" autocomplete="new-password">
<label for="tel">Phone</label>
<input type="tel" id="tel" name="phone" autocomplete="tel">
<button type="submit">Register</button>
</form>
Some of the most commonly used valid values include: "name", "given-name", "family-name", "email", "username", "new-password", "current-password", "street-address", "postal-code", "country", "tel", "cc-number", and "organization". Refer to the full list in the HTML specification for all available options.
The autocomplete attribute tells browsers whether and how to autofill a form field. The HTML specification defines a strict set of valid values for this attribute, known as autofill field names. These include values like "on", "off", "name", "email", "username", "new-password", "current-password", "address-line1", "postal-code", "cc-number", and many others. When you use a value that doesn’t appear in this list — such as "nothanks", "nope", or "false" — the W3C validator reports it as an invalid autofill field name.
A common reason developers use made-up values is frustration with browsers ignoring autocomplete="off". Some browsers (notably Chrome) may still autofill certain fields even when autocomplete="off" is set, particularly for login-related fields. This has led to workarounds using random strings, but these are non-standard and can produce unpredictable behavior across different browsers and assistive technologies.
Why This Matters
- Standards compliance: Invalid attribute values make your HTML non-conforming, which can lead to unexpected browser behavior now or in the future.
- Accessibility: Screen readers and other assistive technologies may use the autocomplete attribute to help users fill in forms. A recognized value like "name" or "email" gives these tools meaningful context, while a random string provides none.
- Browser behavior: Browsers are designed to interpret the standard values. An unrecognized value may be treated inconsistently — some browsers might ignore it, others might treat it as "on", and behavior could change between versions.
How to Fix It
If you want to disable autocomplete, use "off":
<input type="text" name="search" autocomplete="off">
If you want to help browsers autofill correctly, use the appropriate autofill field name from the specification:
<input type="email" name="email" autocomplete="email">
If autocomplete="off" isn’t being respected by the browser (a known issue with some login fields in Chrome), consider these standards-compliant alternatives:
- Use autocomplete="new-password" on password fields where you don’t want saved passwords suggested.
- Use a more specific valid token that doesn’t match what the browser is trying to autofill.
- Use the readonly attribute and remove it on focus via JavaScript as a supplementary measure.
Examples
❌ Invalid: arbitrary string as autocomplete value
<form>
<label for="firstName">First name</label>
<input type="text" name="firstName" id="firstName" autocomplete="nothanks">
<label for="userEmail">Email</label>
<input type="email" name="userEmail" id="userEmail" autocomplete="nope">
</form>
Both "nothanks" and "nope" are not valid autofill field names and will trigger the validation error.
✅ Valid: using "off" to disable autocomplete
<form>
<label for="firstName">First name</label>
<input type="text" name="firstName" id="firstName" autocomplete="off">
<label for="userEmail">Email</label>
<input type="email" name="userEmail" id="userEmail" autocomplete="off">
</form>
✅ Valid: using proper autofill field names
<form>
<label for="firstName">First name</label>
<input type="text" name="firstName" id="firstName" autocomplete="given-name">
<label for="userEmail">Email</label>
<input type="email" name="userEmail" id="userEmail" autocomplete="email">
<label for="newPass">New password</label>
<input type="password" name="newPass" id="newPass" autocomplete="new-password">
</form>
Using descriptive autofill tokens like "given-name", "email", and "new-password" is the best approach when you want browsers and assistive technologies to understand your form fields. For a complete list of valid autofill field names, refer to the WHATWG HTML specification’s autofill section.
The HTML <input> element accepts a specific set of values for its type attribute, as defined by the HTML specification. The value "numeric" is not one of them. When a browser encounters an unrecognized type value, it falls back to type="text", meaning the user gets a plain text field instead of a dedicated numeric input. This fallback behavior means you lose built-in features like increment/decrement spinner controls, numeric keyboard on mobile devices, and native client-side validation that rejects non-numeric entries.
This confusion often arises because of the inputmode="numeric" attribute, which is valid and controls which virtual keyboard appears on mobile devices. The inputmode attribute and the type attribute serve different purposes, and mixing them up leads to this validation error.
Using the correct type="number" value matters for several reasons:
- Accessibility: Screen readers and assistive technologies use the type attribute to announce the expected input format to users.
- User experience: Browsers display appropriate controls (spinners, numeric keypads) for type="number" inputs.
- Validation: Native form validation automatically checks that the entered value is a valid number, within optional min/max bounds and matching an optional step value.
- Standards compliance: Invalid type values cause W3C validation errors and signal potential bugs in your markup.
Examples
Incorrect: using type="numeric"
This triggers the validation error because "numeric" is not a valid type value:
<label for="quantity">Quantity:</label>
<input type="numeric" id="quantity" name="quantity">
The browser will treat this as type="text", so users can type any characters, no spinner controls appear, and no numeric validation occurs.
Correct: using type="number"
Replace "numeric" with "number":
<label for="quantity">Quantity:</label>
<input type="number" id="quantity" name="quantity" min="1" max="10">
This gives you a proper numeric input with optional min, max, and step attributes for constraining the allowed range and increments.
Alternative: using inputmode="numeric" with type="text"
If you need a numeric keyboard on mobile but want more control over the input (for example, accepting values like zip codes or credit card numbers that aren’t truly “numbers”), you can use inputmode="numeric" on a text input instead:
<label for="zip">ZIP Code:</label>
<input type="text" inputmode="numeric" pattern="[0-9]{5}" id="zip" name="zip">
Here, type="text" is valid, inputmode="numeric" triggers the numeric keyboard on mobile devices, and the pattern attribute provides validation. This approach is useful when type="number" isn’t appropriate — for instance, type="number" strips leading zeros and allows scientific notation like 1e5, which is undesirable for codes and identifiers.
Summary of the fix
| Before (invalid) | After (valid) | Use case |
|---|---|---|
| type="numeric" | type="number" | Actual numeric values (quantities, prices, ages) |
| type="numeric" | type="text" inputmode="numeric" | Numeric-looking codes (ZIP, PIN, credit card) |
In most cases, simply changing type="numeric" to type="number" is the correct fix. Choose the inputmode approach only when you specifically need a text field with a numeric keyboard.
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