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 W3C HTML Validator reports this error when it encounters isolang on the <html> element because isolang is not a recognized attribute in any version of HTML. This typically happens when developers attempt to specify the document's language but use an incorrect or made-up attribute name, possibly confusing it with ISO language code terminology.
The correct attribute for declaring a document's language is lang. This attribute accepts a valid BCP 47 language tag, which in most cases is a simple two-letter ISO 639-1 code (like en for English, fr for French, or pt for Portuguese). You can also use extended subtags for regional variants, such as en-US for American English or pt-BR for Brazilian Portuguese.
Setting the lang attribute properly is important for several reasons:
- Accessibility: Screen readers use the
langattribute to select the correct pronunciation rules, ensuring content is read aloud accurately. - SEO: Search engines use the language declaration to serve the right content to users based on their language preferences.
- Browser behavior: Browsers rely on
langfor features like spell-checking, hyphenation, and selecting appropriate default fonts for the given language. - Standards compliance: Only recognized attributes pass W3C validation, and valid markup ensures consistent, predictable behavior across browsers.
To fix this issue, simply replace isolang with lang on your <html> element. Keep the same language code value—it's the attribute name that's wrong, not the value.
Examples
❌ Incorrect: Using the invalid isolang attribute
<!DOCTYPE html>
<htmlisolang="pt">
<head>
<title>Minha Página</title>
</head>
<body>
<p>Olá, mundo!</p>
</body>
</html>
This triggers the error: Attribute "isolang" not allowed on element "html" at this point.
✅ Correct: Using the lang attribute
<!DOCTYPE html>
<htmllang="pt">
<head>
<title>Minha Página</title>
</head>
<body>
<p>Olá, mundo!</p>
</body>
</html>
✅ Correct: Using a regional language subtag
<!DOCTYPE html>
<htmllang="pt-BR">
<head>
<title>Minha Página</title>
</head>
<body>
<p>Olá, mundo!</p>
</body>
</html>
Common language codes
Here are some frequently used ISO 639-1 language codes for the lang attribute:
en— Englishes— Spanishfr— Frenchde— Germanpt— Portuguesezh— Chineseja— Japanesear— Arabicko— Koreanru— Russian
The aria-labelledby attribute is part of the WAI-ARIA specification and provides an accessible name for an element by referencing the id values of other elements that contain the labeling text. Without the aria- prefix, labelledby is simply an unrecognized attribute that browsers and assistive technologies will ignore. This means your SVG graphic won't have the accessible label you intended, leaving screen reader users without a meaningful description of the content.
This issue is especially important for <svg> elements because SVG graphics are often used for icons, charts, and illustrations that need descriptive labels for accessibility. Using the incorrect attribute name means the graphic is effectively unlabeled for users who rely on assistive technology.
How to Fix It
Replace labelledby with aria-labelledby on your <svg> element. The attribute's value should be a space-separated list of one or more id values that reference elements containing the label text.
If you want to label an SVG using text that's already visible on the page, aria-labelledby is the ideal approach. You can also reference a <title> element inside the SVG itself.
Examples
❌ Incorrect: Using labelledby (invalid attribute)
<h2id="chart-title">Monthly Sales</h2>
<svglabelledby="chart-title"role="img"viewBox="0 0 200 100">
<!-- chart content -->
</svg>
✅ Correct: Using aria-labelledby to reference an external heading
<h2id="chart-title">Monthly Sales</h2>
<svgaria-labelledby="chart-title"role="img"viewBox="0 0 200 100">
<!-- chart content -->
</svg>
✅ Correct: Using aria-labelledby to reference the SVG's own <title>
<svgaria-labelledby="icon-title"role="img"viewBox="0 0 24 24">
<titleid="icon-title">Search</title>
<pathd="M15.5 14h-.79l-.28-.27A6.47 6.47 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5z"/>
</svg>
✅ Correct: Referencing multiple label sources
You can combine multiple id values to build a composite accessible name, separated by spaces:
<h2id="section-title">Revenue</h2>
<pid="section-desc">Q1 2024 revenue by region</p>
<svgaria-labelledby="section-title section-desc"role="img"viewBox="0 0 400 200">
<!-- chart content -->
</svg>
In this case, a screen reader would announce something like "Revenue Q1 2024 revenue by region" as the accessible name for the SVG.
Tips
- When using
aria-labelledbyon<svg>, also addrole="img"to ensure consistent behavior across screen readers. - If the SVG is purely decorative, use
aria-hidden="true"instead of labeling it. - The
aria-labelledbyattribute overrides other labeling mechanisms likearia-labelor the<title>element, so use it when you want a specific label to take precedence.
The maxlength attribute provides built-in client-side validation that caps the number of characters a user can type into a field. Browsers enforce this by preventing further input once the limit is reached. However, this behavior only makes sense for input types that accept arbitrary text strings. Input types like number, date, range, and checkbox have their own value formats and constraints — a number input's value is controlled by min, max, and step, not by character count.
When you place maxlength on an unsupported input type, browsers will ignore the attribute. This means it provides no actual validation while giving a false sense of security. It also produces invalid HTML, which can cause issues with assistive technologies that may try to interpret the attribute and relay incorrect information to users. Keeping your markup valid ensures predictable behavior across browsers and a better experience for all users.
How to fix it
- Remove
maxlengthfrom any<input>whosetypeis notemail,password,search,tel,text, orurl. - Use the correct constraint attributes for the input type in question. For
numberinputs, useminandmax. Fordateinputs, useminandmaxwith date strings. - If you genuinely need character-length validation, consider whether a text-based input type is more appropriate for your use case, or implement the constraint in JavaScript.
Examples
❌ Invalid: maxlength on a number input
<labelfor="quantity">Quantity</label>
<inputtype="number"id="quantity"name="quantity"maxlength="3">
The number type does not support maxlength. Browsers will ignore it, and the HTML is invalid.
✅ Fixed: using min and max for a number input
<labelfor="quantity">Quantity</label>
<inputtype="number"id="quantity"name="quantity"min="0"max="999">
If the goal was to limit the value to three digits, min and max are the correct constraints.
❌ Invalid: maxlength on a date input
<labelfor="start-date">Start date</label>
<inputtype="date"id="start-date"name="start-date"maxlength="10">
Date inputs have a browser-provided date picker, and their values are always in YYYY-MM-DD format. The maxlength attribute has no effect here.
✅ Fixed: using min and max for a date input
<labelfor="start-date">Start date</label>
<inputtype="date"id="start-date"name="start-date"min="2020-01-01"max="2030-12-31">
❌ Invalid: maxlength on a checkbox
<label>
<inputtype="checkbox"name="agree"maxlength="1"> I agree
</label>
A checkbox is a boolean toggle — character length is meaningless here.
✅ Fixed: removing the invalid attribute
<label>
<inputtype="checkbox"name="agree"> I agree
</label>
✅ Valid: maxlength on supported text-based types
<labelfor="username">Username</label>
<inputtype="text"id="username"name="username"maxlength="30">
<labelfor="user-email">Email</label>
<inputtype="email"id="user-email"name="email"maxlength="254">
<labelfor="user-phone">Phone</label>
<inputtype="tel"id="user-phone"name="phone"maxlength="15">
<labelfor="site-url">Website</label>
<inputtype="url"id="site-url"name="website"maxlength="2048">
<labelfor="user-pass">Password</label>
<inputtype="password"id="user-pass"name="password"maxlength="128">
<labelfor="query">Search</label>
<inputtype="search"id="query"name="q"maxlength="100">
All six of these input types support maxlength because they accept free-form text where limiting character count is meaningful.
The minlength attribute defines the minimum number of characters (as UTF-16 code units) that a user can enter into a text-based input field. It provides built-in client-side validation without requiring JavaScript. However, it only makes sense on input types where the user is typing free-form text. For input types like number, date, color, range, or checkbox, the concept of a minimum character length doesn't apply — these inputs have their own constrained value formats or use other attributes like min and max for validation.
When the W3C validator encounters minlength on an unsupported input type, it flags the attribute as invalid. Browsers will typically ignore the attribute silently, meaning your intended validation won't actually work. This can lead to a false sense of security where you believe the input is being validated when it isn't.
The minlength value must be a non-negative integer (0 or higher) and must be less than or equal to maxlength if both are specified. The minlength attribute also works on <textarea> elements.
Examples
❌ Incorrect: minlength on a number input
The number input type doesn't support minlength. If you want to enforce a minimum value, use the min attribute instead.
<labelfor="age">Enter your age</label>
<inputtype="number"minlength="1"id="age">
✅ Fixed: Using min for number inputs
<labelfor="age">Enter your age</label>
<inputtype="number"min="1"id="age">
❌ Incorrect: minlength on a date input
<labelfor="start-date">Start date</label>
<inputtype="date"minlength="10"id="start-date">
✅ Fixed: Remove minlength from date inputs
Date inputs have a browser-controlled format, so character length constraints don't apply. Use min and max to constrain the date range.
<labelfor="start-date">Start date</label>
<inputtype="date"min="2024-01-01"id="start-date">
✅ Correct: minlength on supported input types
Here are valid uses of minlength across all supported input types:
<labelfor="username">Username (at least 3 characters)</label>
<inputtype="text"minlength="3"id="username">
<labelfor="email">Email</label>
<inputtype="email"minlength="5"id="email">
<labelfor="pass">Password (at least 8 characters)</label>
<inputtype="password"minlength="8"id="pass">
<labelfor="phone">Phone number</label>
<inputtype="tel"minlength="7"id="phone">
<labelfor="query">Search</label>
<inputtype="search"minlength="2"id="query">
<labelfor="website">Website URL</label>
<inputtype="url"minlength="10"id="website">
✅ Correct: minlength with maxlength on a textarea
<labelfor="bio">Bio (between 10 and 200 characters)</label>
<textareaminlength="10"maxlength="200"id="bio"></textarea>
Quick Reference
| Input Type | Supports minlength? | Alternative |
|---|---|---|
text, email, password, search, tel, url | ✅ Yes | — |
textarea | ✅ Yes | — |
number, range | ❌ No | Use min / max |
date, datetime-local, time, month, week | ❌ No | Use min / max |
checkbox, radio | ❌ No | Use required |
file | ❌ No | Validate with JavaScript |
color, hidden | ❌ No | Not applicable |
This error is misleading at first glance because the <meta> tag in question is often perfectly well-formed. The real problem is usually above the <meta> tag — an element that doesn't belong in <head> (such as <img>, <div>, <p>, or other flow content) has been placed there. When the HTML parser encounters such an element inside <head>, it implicitly closes the <head> and opens the <body>. From that point on, any subsequent <meta> tags are now technically inside the <body>, where the name attribute on <meta> is not permitted.
In other cases, the error can also occur when a <meta name="..."> tag is explicitly placed inside <body>, or when a typo or malformed tag earlier in the document breaks the expected document structure.
This matters for several reasons. Search engines and social media platforms rely on <meta> tags being in the <head> to extract page descriptions, Open Graph data, and other metadata. If the document structure is broken and <meta> tags end up in the <body>, this metadata may be ignored entirely. Additionally, elements like <img> inside <head> won't render as expected, and the overall document structure will be invalid, potentially causing unpredictable behavior across browsers.
How to fix it
- Look above the flagged
<meta>tag. Find any element in the<head>that doesn't belong there — common culprits include<img>,<div>,<span>,<p>,<a>, or<section>. - Move the offending element into the
<body>where it belongs. - If the
<meta>tag itself is in the<body>, move it into the<head>. - Check for malformed tags above the
<meta>— an unclosed tag or a typo can break the parser's understanding of the document structure.
Only certain elements are allowed inside <head>: <title>, <meta>, <link>, <style>, <script>, <noscript>, <base>, and <template>.
Examples
An invalid element in <head> breaks the context
The <img> tag is not allowed inside <head>. The parser implicitly closes <head> when it encounters it, so the <meta> tag that follows ends up in <body>:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<imgsrc="photo.jpg"alt="A smiling cat">
<metaname="description"content="A page about cats">
</head>
<body>
<p>Welcome!</p>
</body>
</html>
Move the <img> into the <body> to fix the issue:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<metaname="description"content="A page about cats">
</head>
<body>
<imgsrc="photo.jpg"alt="A smiling cat">
<p>Welcome!</p>
</body>
</html>
A <meta> tag accidentally placed in <body>
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
</head>
<body>
<metaname="author"content="Jane Doe">
<p>Hello world</p>
</body>
</html>
Move the <meta> tag into <head>:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<metaname="author"content="Jane Doe">
</head>
<body>
<p>Hello world</p>
</body>
</html>
A malformed tag disrupts the <head>
A missing closing > on a <link> tag can confuse the parser, causing subsequent elements to be misinterpreted:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<linkrel="stylesheet"href="style.css"
<metaname="viewport"content="width=device-width, initial-scale=1">
</head>
<body>
<p>Content</p>
</body>
</html>
Close the <link> tag properly:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<linkrel="stylesheet"href="style.css">
<metaname="viewport"content="width=device-width, initial-scale=1">
</head>
<body>
<p>Content</p>
</body>
</html>
When the HTML parser encounters a < character inside an opening tag, it doesn't treat it as the start of a new tag — instead, it tries to interpret it as an attribute name. Since < is not a valid attribute name, the W3C validator raises this error. The browser may still render the page, but the behavior is undefined and can vary across different browsers, potentially leading to broken markup or elements that don't display correctly.
This issue most commonly occurs in a few scenarios:
- Accidental keystrokes — a stray
<typed while editing attributes. - Copy-paste artifacts — fragments of other tags getting pasted into the middle of an element.
- Misplaced angle brackets — attempting to nest or close tags incorrectly, such as adding
<before/>in a self-closing tag. - Template or code generation errors — dynamic HTML output that incorrectly injects
<into attribute positions.
Because this is a syntax-level problem, it can cause cascading parse errors. The parser may misinterpret everything after the stray < until it finds a matching >, which can swallow subsequent elements or attributes and produce unexpected rendering results.
How to Fix It
- Open the file referenced by the validator error and go to the indicated line number.
- Look inside the opening tag of the flagged element for a
<character that doesn't belong. - Remove the stray
<character. - If the
<was meant to represent a literal less-than sign in an attribute value, replace it with the HTML entity<.
Examples
Stray < before the closing slash
<!-- ❌ Stray "<" before the self-closing slash -->
<imgsrc="photo.jpg"alt="smiling cat"</>
<!-- ✅ Fixed: removed the stray "<" -->
<imgsrc="photo.jpg"alt="smiling cat"/>
Stray < between attributes
<!-- ❌ Accidental "<" between attributes -->
<ahref="/about"<class="nav-link">About</a>
<!-- ✅ Fixed: removed the stray "<" -->
<ahref="/about"class="nav-link">About</a>
Fragment of another tag pasted inside an element
<!-- ❌ Leftover "<span" pasted inside the div's opening tag -->
<divclass="card"<span>
<p>Hello world</p>
</div>
<!-- ✅ Fixed: removed the pasted fragment -->
<divclass="card">
<p>Hello world</p>
</div>
Literal < intended in an attribute value
If you actually need a less-than sign inside an attribute value — for example, in a title or data-* attribute — use the < entity instead of a raw <.
<!-- ❌ Raw "<" in an attribute value can cause parsing issues -->
<spantitle="x < 10">Threshold</span>
<!-- ✅ Fixed: use the HTML entity -->
<spantitle="x < 10">Threshold</span>
The ontouchstart attribute is an inline event handler that some developers use to detect when a user touches an element on a touchscreen device. However, unlike standard event handler attributes such as onclick, onmousedown, or onkeydown, the ontouchstart attribute is not defined in the HTML specification. The W3C validator flags it because only attributes explicitly listed in the spec are allowed on a given element.
The touchstart event itself is a legitimate event defined in the Touch Events specification — it's the inline HTML attribute form (ontouchstart) that isn't recognized as a valid attribute by the HTML standard. This distinction is important: you can absolutely listen for touchstart events, just not via an inline attribute on an HTML element.
Why This Is a Problem
- Standards compliance: Using non-standard attributes produces invalid HTML, which can cause issues with automated testing, accessibility audits, and content management pipelines that enforce validation.
- Accessibility: Relying solely on touch events excludes users who navigate with a keyboard, mouse, or assistive technology. Touch-only handlers can make interactive elements completely inaccessible to non-touch users.
- Maintainability: Inline event handlers mix behavior with markup, making code harder to maintain and debug compared to centralized JavaScript event listeners.
- Browser inconsistencies: While most mobile browsers support the
touchstartevent, the inline attribute form is not guaranteed to work consistently across all environments.
How to Fix It
- Remove the inline
ontouchstartattribute from your HTML element. - Use
addEventListenerin JavaScript to attach thetouchstartevent listener programmatically. - Consider also handling
clickorpointerdownevents so the interaction works for all input types — mouse, keyboard, touch, and stylus. The Pointer Events API (pointerdown,pointerup, etc.) is a modern, unified approach that covers mouse, touch, and pen input in a single event model.
Examples
❌ Invalid: Inline ontouchstart attribute
<divontouchstart="handleTouch()">Tap me</div>
This triggers the validation error because ontouchstart is not a recognized attribute in the HTML specification.
✅ Valid: Using addEventListener for touchstart
<divid="touch-target">Tap me</div>
<script>
document.getElementById("touch-target").addEventListener("touchstart",function(event){
// Handle touch interaction
});
</script>
The touchstart event is attached through JavaScript, keeping the HTML valid and clean.
✅ Valid: Using Pointer Events for cross-input support
<buttonid="action-btn"type="button">Tap or click me</button>
<script>
document.getElementById("action-btn").addEventListener("pointerdown",function(event){
// Handles mouse, touch, and pen input
});
</script>
Using pointerdown instead of touchstart provides a single handler that works across all input types. Note also the use of a <button> element, which is natively focusable and accessible, making it a better choice than a <div> for interactive elements.
✅ Valid: Supporting both touch and non-touch with separate listeners
<divid="interactive-area"role="button"tabindex="0">Interact with me</div>
<script>
varel=document.getElementById("interactive-area");
el.addEventListener("touchstart",function(event){
// Handle touch-specific interaction
});
el.addEventListener("click",function(event){
// Handle mouse and keyboard interaction
});
</script>
If you must use a <div> as an interactive element, add role="button" and tabindex="0" for accessibility, and attach both touchstart and click listeners to cover all input methods.
The pattern attribute provides a powerful way to add client-side form validation directly in HTML without relying on JavaScript. It accepts a regular expression that the browser uses to validate user input before the form is submitted. However, the HTML specification restricts pattern to input types where the user enters free-form text. Input types like number, date, range, color, and checkbox have their own built-in validation mechanisms (such as min, max, and step), so applying a regex pattern to them is meaningless and invalid.
When you add pattern to an unsupported input type, browsers will simply ignore it. This means you might think you have validation in place when you actually don't, which can lead to unexpected invalid data being submitted. Removing the invalid attribute also keeps your markup clean and standards-compliant, which benefits accessibility tools and future browser behavior.
Why certain types don't support pattern
number— Values are constrained bymin,max, andstep. The browser enforces numeric input natively.date,time,datetime-local,month,week— These use date/time pickers with their own format and range constraints.range— A slider control already constrained bymin,max, andstep.checkbox,radio— These are toggled on/off or selected from a group; a regex pattern doesn't apply.file— File selection is handled by the OS file picker; use theacceptattribute instead.color— Uses a color picker with a fixed hex format.hidden— Not user-editable, so client-side validation is irrelevant.
How to fix it
- Remove the
patternattribute if the input type already provides sufficient validation through its native controls. - Change the input
typeto one of the six supported types (email,password,search,tel,text, orurl) if you genuinely need regex-based validation. - Use alternative attributes like
min,max,step, oracceptthat are designed for the specific input type. - Use JavaScript validation if you need custom validation logic that goes beyond what native attributes offer.
Examples
❌ Incorrect: pattern on a number input
<labelfor="qty">Quantity (multiples of 5):</label>
<inputtype="number"id="qty"name="qty"pattern="[0-9]+"min="0"max="100">
The pattern attribute is not allowed on type="number". Since min, max, and step already handle numeric constraints, pattern is unnecessary here.
✅ Correct: using step instead of pattern for number validation
<labelfor="qty">Quantity (multiples of 5):</label>
<inputtype="number"id="qty"name="qty"min="0"max="100"step="5">
❌ Incorrect: pattern on a date input
<labelfor="dob">Date of birth:</label>
<inputtype="date"id="dob"name="dob"pattern="\d{4}-\d{2}-\d{2}">
The date input type already enforces a date format through its native picker, so pattern is invalid here.
✅ Correct: removing pattern from date input
<labelfor="dob">Date of birth:</label>
<inputtype="date"id="dob"name="dob"min="1900-01-01"max="2025-12-31">
❌ Incorrect: pattern on a checkbox input
<label>
<inputtype="checkbox"name="agree"pattern=".+"> I agree to the terms
</label>
✅ Correct: using required instead of pattern for checkbox
<label>
<inputtype="checkbox"name="agree"required> I agree to the terms
</label>
✅ Correct: pattern on a supported text input
<labelfor="zip">ZIP code:</label>
<inputtype="text"id="zip"name="zip"pattern="[0-9]{5}"title="Five digit ZIP code"required>
When using pattern on a supported input type, always include a title attribute that describes the expected format. Browsers display the title text as part of the validation error message, helping users understand what input is expected.
The placeholder attribute provides a short hint describing the expected value of an input field. This hint is displayed inside the control as light, greyed-out text when the field is empty and loses focus. It only makes sense on input types that present a visible text entry area where the user types characters directly. Input types like checkbox, radio, range, color, file, hidden, date, datetime-local, month, week, time, and image either don't display a text field at all or use a specialized UI widget (like a date picker or file selector), so the browser has nowhere to render placeholder text.
Using placeholder on an unsupported input type violates the HTML specification as defined by WHATWG. While browsers will typically just ignore the invalid attribute, it signals a likely mistake in your markup — perhaps the input type is wrong, or the hint should be conveyed differently (e.g., via a <label> or adjacent text). Keeping your HTML valid also improves maintainability, helps assistive technologies parse your page correctly, and prevents unexpected behavior if future browser versions handle invalid attributes differently.
It's also worth noting that even on supported input types, placeholder should not be used as a replacement for <label>. Placeholder text disappears as soon as the user starts typing, which can cause usability and accessibility issues. Always pair your inputs with a proper <label> element.
How to fix it
- Remove the
placeholderattribute if it's on an input type that doesn't support it. - Change the input type to one that supports
placeholderif the current type is incorrect. - Use a
<label>or visible helper text to convey the hint instead, especially for non-text input types.
Examples
Invalid: placeholder on a hidden input
A hidden input is never visible to the user, so a placeholder serves no purpose.
<inputtype="hidden"name="token"placeholder="Session token">
Fixed: Remove the placeholder attribute.
<inputtype="hidden"name="token">
Invalid: placeholder on a checkbox
Checkboxes don't have a text entry area, so there's nowhere for placeholder text to appear.
<label>
<inputtype="checkbox"name="agree"placeholder="Check to agree"> I agree
</label>
Fixed: Remove the placeholder and rely on the label text to convey the hint.
<label>
<inputtype="checkbox"name="agree"> I agree to the terms
</label>
Invalid: placeholder on a date input
Date inputs use a browser-provided date picker widget, not a free-text field.
<labelfor="birthday">Birthday</label>
<inputtype="date"id="birthday"name="birthday"placeholder="YYYY-MM-DD">
Fixed: Remove the placeholder. If you need to show a format hint, use a separate element.
<labelfor="birthday">Birthday</label>
<inputtype="date"id="birthday"name="birthday">
<small>Format: YYYY-MM-DD</small>
Invalid: placeholder on a file input
<labelfor="upload">Upload</label>
<inputtype="file"id="upload"name="upload"placeholder="Choose a file">
Fixed: Remove the placeholder. The browser provides its own label for file inputs (e.g., "No file chosen").
<labelfor="upload">Upload</label>
<inputtype="file"id="upload"name="upload">
Valid: placeholder on supported input types
These are all valid uses of the placeholder attribute:
<labelfor="email">Email</label>
<inputtype="email"id="email"name="email"placeholder="you@example.com">
<labelfor="phone">Phone</label>
<inputtype="tel"id="phone"name="phone"placeholder="+1 (555) 123-4567">
<labelfor="site">Website</label>
<inputtype="url"id="site"name="site"placeholder="https://example.com">
<labelfor="query">Search</label>
<inputtype="search"id="query"name="query"placeholder="Search articles…">
<labelfor="qty">Quantity</label>
<inputtype="number"id="qty"name="qty"placeholder="1">
<labelfor="pw">Password</label>
<inputtype="password"id="pw"name="pw"placeholder="Enter your password">
The HTML specification restricts the readonly attribute to input types where the user would normally type or select a textual/numeric/date value. The idea is straightforward: readonly means "you can see and select this value, but you can't edit it." That concept only makes sense for fields that contain editable text or structured data like dates and numbers. For controls like checkboxes, radio buttons, color pickers, file selectors, and range sliders, the interaction model is fundamentally different — there's no text to make "read-only."
The full list of input types that support readonly is:
textsearchurltelemailpassworddatemonthweektimedatetime-localnumber
The readonly attribute is not valid on these types: checkbox, radio, range, color, file, hidden, button, submit, reset, and image.
Why this matters
Standards compliance: Browsers are not required to honor readonly on unsupported input types. Even if a browser appears to respect it today, that behavior is not guaranteed and could change.
Form submission behavior: There's a critical difference between readonly and disabled. A readonly field's value is included in form submission data, while a disabled field's value is not. If you swap readonly for disabled to fix this error, be aware that the field's value won't be sent with the form unless you take additional steps (such as adding a hidden input).
Accessibility: Screen readers and assistive technologies rely on valid HTML to convey the correct state of form controls. Using readonly on an unsupported type can send confusing signals about the control's interactivity.
How to fix it
You have several options depending on your goal:
- Remove
readonlyif it was added by mistake or isn't necessary. - Change the input type to one that supports
readonly, if that fits your use case. - Use
disabledinstead to prevent interaction on non-textual inputs. Remember that disabled fields are excluded from form submission. - Pair
disabledwith a hidden input if you need the value submitted with the form but want the visible control to be non-interactive.
Examples
Invalid: readonly on a checkbox
<inputtype="checkbox"name="agree"readonly>
Invalid: readonly on a range input
<inputtype="range"name="volume"min="0"max="100"value="50"readonly>
Invalid: readonly on a color input
<inputtype="color"name="theme"value="#ff0000"readonly>
Fixed: using readonly on a supported input type
<inputtype="text"name="code"value="ABC-123"readonly>
<inputtype="email"name="contact"value="user@example.com"readonly>
<inputtype="date"name="start"value="2024-01-15"readonly>
Fixed: using disabled for a non-textual input
<inputtype="checkbox"name="agree"checkeddisabled>
Fixed: using disabled with a hidden input to preserve form submission
If you need the value to be submitted with the form while keeping the visible control non-interactive, pair a disabled control with a hidden input:
<!-- The hidden input ensures the value is submitted -->
<inputtype="hidden"name="agree"value="on">
<!-- The disabled checkbox is visible but non-interactive -->
<inputtype="checkbox"name="agree_display"checkeddisabled>
<labelfor="agree_display">I agree to the terms</label>
Fixed: using JavaScript to prevent changes (advanced)
If you truly need a checkbox that looks interactive but can't be changed, you can use JavaScript while keeping the HTML valid:
<inputtype="checkbox"name="agree"checkedonclick="returnfalse;">
Note that this approach relies on JavaScript and won't work if scripting is disabled. For most cases, using disabled (with or without a companion hidden input) is the simpler and more robust solution.
The required attribute is a boolean attribute that tells the browser a field must be filled in before the form can be submitted. However, not every input type supports this concept. Some input types always have a value (like range, which defaults to a midpoint, or color, which defaults to #000000), while others represent actions rather than user data (like submit, reset, image, and button). For hidden inputs, the user has no way to interact with the field at all, so requiring them to provide a value makes no sense.
The HTML specification explicitly limits required to the following input types: checkbox, date, datetime-local, email, file, month, number, password, radio, search, tel, text, time, url, and week.
Using required on an unsupported type is invalid HTML. Browsers will typically ignore the attribute in this situation, which means you might believe a field is required when it actually isn't being validated at all. This can lead to forms being submitted with missing or unexpected data. It also creates confusion for assistive technologies — screen readers may announce a field as required even though the browser won't enforce it, misleading users.
How to fix it
- Check the input type. If you're using
requiredon an input with a type likehidden,range,color,submit,reset,image, orbutton, the attribute is not allowed. - Remove the
requiredattribute if the input type inherently provides a value or doesn't accept user-provided data. - Change the input type if you actually need the field to be required and the current type doesn't match your intent.
- Use server-side validation for inputs like
hiddenthat can't userequiredbut still need a value.
Examples
❌ Invalid: required on a hidden input
<form>
<inputtype="hidden"name="token"required>
<buttontype="submit">Submit</button>
</form>
The user cannot interact with a hidden input, so required is not allowed here. The browser won't enforce it.
❌ Invalid: required on a range input
<form>
<labelfor="volume">Volume:</label>
<inputtype="range"id="volume"name="volume"min="0"max="100"required>
<buttontype="submit">Submit</button>
</form>
A range input always has a value (it defaults to the midpoint), so required is meaningless and not permitted.
❌ Invalid: required on a color input
<form>
<labelfor="color">Pick a color:</label>
<inputtype="color"id="color"name="color"required>
<buttontype="submit">Submit</button>
</form>
A color input always has a value (defaulting to #000000), so required is not valid here.
✅ Valid: required removed from unsupported types
<form>
<inputtype="hidden"name="token"value="abc123">
<labelfor="volume">Volume:</label>
<inputtype="range"id="volume"name="volume"min="0"max="100">
<buttontype="submit">Submit</button>
</form>
✅ Valid: required on supported input types
<form>
<labelfor="email">Email:</label>
<inputtype="email"id="email"name="email"required>
<labelfor="dob">Date of birth:</label>
<inputtype="date"id="dob"name="dob"required>
<label>
<inputtype="checkbox"name="terms"required>
I agree to the terms
</label>
<buttontype="submit">Submit</button>
</form>
These input types — email, date, and checkbox — all accept direct user input and are on the allowed list for the required attribute.
The seamless attribute was originally drafted as part of the HTML5 specification to allow an <iframe> to appear as though its content were part of the containing document. When present, it was supposed to remove borders, inherit styles from the parent page, and allow the iframe content to participate in the parent document's styling context. However, no browser ever fully implemented the attribute, and it was officially removed from the WHATWG HTML Living Standard.
Because seamless is not a recognized attribute in the current HTML specification, using it triggers a validation error. Beyond validation, including it has no practical effect in any modern browser — it's simply ignored. Keeping unsupported attributes in your markup creates confusion for other developers who may assume the attribute is doing something meaningful. It also adds unnecessary clutter to your HTML.
How to Fix It
Remove the seamless attribute from any <iframe> elements. If you want to replicate the visual effects that seamless was intended to provide, you can use CSS:
- Remove the border: Apply
border: none;or use theframeborder="0"attribute (thoughframeborderis also obsolete — CSS is preferred). - Blend the background: Set
background: transparent;and add theallowtransparencyattribute if targeting older browsers. - Auto-resize to content: Use JavaScript to dynamically adjust the iframe's height based on its content (subject to same-origin restrictions).
Note that true seamless integration — where the iframe inherits parent styles and its content flows naturally within the parent document — is not achievable with standard iframe behavior. If you need that level of integration, consider including the content directly in the page, using a server-side include, or fetching the content with JavaScript via the fetch API and inserting it into the DOM.
Examples
❌ Invalid: Using the seamless attribute
<iframesrc="widget.html"seamless></iframe>
✅ Fixed: Attribute removed, CSS used for styling
<iframesrc="widget.html"style="border: none;"></iframe>
✅ Fixed: Using a CSS class for cleaner markup
<style>
.seamless-iframe{
border: none;
width:100%;
background: transparent;
}
</style>
<iframesrc="widget.html"class="seamless-iframe"title="Embedded widget"></iframe>
✅ Alternative: Embedding content directly instead of using an iframe
If the content is on the same origin and you need true seamless integration, consider loading it directly:
<divid="embedded-content">
<!-- Content loaded via server-side include or JavaScript fetch -->
</div>
HTML has a defined set of global attributes (such as id, class, lang, and title) and element-specific attributes. Any attribute that isn't part of these recognized sets will trigger a validation error. The st_title attribute is a proprietary, non-standard attribute that was used by older versions of the ShareThis sharing widget to pass metadata — specifically, the title of the content being shared.
The HTML5 specification introduced data-* attributes as the standard mechanism for embedding custom data on elements. These attributes allow developers to store arbitrary information without conflicting with the HTML spec. Newer versions of ShareThis and similar services have adopted this convention, but legacy code — especially in CMS themes, plugins, or modules — may still use the old non-standard format.
Using invalid attributes causes several problems:
- Standards compliance: The document fails W3C validation, which can indicate deeper markup quality issues.
- Future compatibility: Browsers are not required to handle non-standard attributes in any predictable way. Future browser updates could ignore or strip them.
- Maintainability: Non-standard attributes make code harder for other developers to understand and maintain.
- Accessibility tools: Screen readers and other assistive technologies rely on well-formed HTML. Invalid attributes can cause unexpected behavior in these tools.
To fix this, replace all proprietary ShareThis attributes with their data-* equivalents. For example, st_title becomes data-st-title, st_url becomes data-st-url, and displayText becomes data-st-displaytext. You should also update the ShareThis JavaScript library to a version that recognizes the new attribute format.
Examples
❌ Invalid: Using proprietary attributes
<spanclass="st_sharethis"st_title="My Article"st_url="https://example.com/article"displayText="ShareThis">
Share
</span>
This triggers validation errors for st_title, st_url, and displayText because none of these are valid HTML attributes.
✅ Valid: Using data-* attributes
<spanclass="st_sharethis"data-st-title="My Article"data-st-url="https://example.com/article"data-st-displaytext="ShareThis">
Share
</span>
All custom data is now stored in properly namespaced data-* attributes, which are fully compliant with the HTML5 specification.
✅ Valid: Using a button element with data-* attributes
If the element is interactive (e.g., it triggers a share action on click), consider using a <button> instead of a <span> for better accessibility:
<buttontype="button"class="st_sharethis"data-st-title="My Article"data-st-url="https://example.com/article">
Share this article
</button>
Fixing this in a CMS
If you're using Drupal, WordPress, or another CMS with a ShareThis module or plugin:
- Update the plugin/module to the latest version — most have already migrated to
data-*attributes. - Check your theme templates for hardcoded ShareThis markup that may still use the old attribute format.
- Search your codebase for
st_title,st_url, anddisplayTextand replace them withdata-st-title,data-st-url, anddata-st-displaytextrespectively. - Update the ShareThis JavaScript to a version compatible with the new attribute names, and verify that sharing functionality still works after the change.
HTML has a defined set of global attributes (like class, id, title, lang, etc.) and element-specific attributes that are permitted by the specification. Any attribute that falls outside this set — such as st_url, st_title, or displayText — will trigger a validation error because the browser and the validator don't recognize it as part of the HTML standard.
The st_url attribute, along with related attributes like st_title, st_via, and displayText, originated from early versions of the ShareThis social sharing library. These were proprietary attributes that the ShareThis JavaScript would read from the DOM to configure sharing behavior. While browsers generally ignore attributes they don't understand (so the page may still appear to work), using non-standard attributes violates the HTML specification and can cause several problems:
- Standards compliance: Invalid HTML can lead to unpredictable behavior across different browsers and future browser versions.
- Accessibility: Screen readers and other assistive technologies may not handle non-standard attributes correctly, potentially causing confusion.
- Maintainability: Non-standard markup is harder for other developers to understand and maintain.
- SEO: Search engine crawlers may penalize or misinterpret pages with significant validation errors.
HTML5 introduced data-* attributes specifically to solve this problem. Any custom data you need to attach to an element can use this pattern — for example, data-st-url instead of st_url. The ShareThis library itself updated its integration to use data-* attributes in later versions, so modern implementations should already follow this pattern.
How to Fix
- Replace proprietary attributes with
data-*equivalents: Convertst_urltodata-st-url,st_titletodata-st-title,displayTexttodata-display-text, and so on. - Update your ShareThis integration: If you're using an outdated version of ShareThis (or an outdated CMS module/plugin like an old Drupal integration), update to the latest version, which uses valid HTML5 attributes.
- Check your CMS templates: If the invalid attributes are hardcoded in a theme template or a content block, update them manually.
Examples
Invalid: Proprietary attributes on a <span>
<spanclass="st_facebook_large"displayText="Facebook"st_url="https://example.com"st_title="My Page Title"></span>
<spanclass="st_twitter_large"displayText="Twitter"st_url="https://example.com"st_title="My Page Title"></span>
This markup uses st_url, st_title, and displayText, none of which are valid HTML attributes.
Valid: Using data-* attributes instead
<spanclass="st_facebook_large"data-display-text="Facebook"data-st-url="https://example.com"data-st-title="My Page Title"></span>
<spanclass="st_twitter_large"data-display-text="Twitter"data-st-url="https://example.com"data-st-title="My Page Title"></span>
By prefixing each custom attribute with data-, the markup becomes valid HTML5. Note that you may also need to update the associated JavaScript to read from these new attribute names (e.g., using element.dataset.stUrl instead of element.getAttribute('st_url')).
Valid: Modern ShareThis integration
If you're updating your ShareThis integration entirely, the modern approach uses a different markup pattern:
<divclass="sharethis-inline-share-buttons"data-url="https://example.com"data-title="My Page Title"></div>
Modern versions of the ShareThis library expect data-* attributes by default, so upgrading the library and its associated markup is the cleanest solution. Check the ShareThis documentation for the latest recommended integration approach for your platform.
The type attribute is specific to the <input> element, where it determines the kind of input control rendered — such as text, checkbox, email, or number. The <textarea> element serves a single, distinct purpose: providing a multi-line plain-text editing area. Because it doesn't have multiple modes of operation, the HTML specification does not define a type attribute for it.
This error commonly occurs when developers confuse <textarea> with <input>, or when refactoring a single-line <input type="text"> into a multi-line <textarea> without removing the now-invalid type attribute. It can also appear when using templating systems or frameworks that apply attributes generically across different form elements.
While browsers will typically ignore the unrecognized type attribute on a <textarea>, keeping it in your markup causes W3C validation errors and can lead to confusion for other developers reading the code. Invalid attributes may also interfere with CSS attribute selectors (e.g., textarea[type="text"] is a selector targeting invalid markup), accessibility tools, or automated testing systems that rely on well-formed HTML.
To fix this issue, remove the type attribute from the <textarea> element. If you need to differentiate between multiple textareas, use id, name, or class attributes instead. If you actually need a single-line text input, use <input type="text"> rather than <textarea>.
Examples
Incorrect: type attribute on <textarea>
<labelfor="comment">Your comment:</label>
<textareatype="text"id="comment"name="comment"rows="4"cols="50"></textarea>
The type="text" attribute is not valid on <textarea> and will trigger a validation error.
Correct: <textarea> without type
<labelfor="comment">Your comment:</label>
<textareaid="comment"name="comment"rows="4"cols="50"></textarea>
Simply removing the type attribute resolves the issue. The <textarea> element inherently provides a multi-line text input, so no type is needed.
Correct: Using <input> when a single-line field is intended
If you intended a single-line text field, use <input> instead:
<labelfor="username">Username:</label>
<inputtype="text"id="username"name="username">
The type attribute is valid and expected on <input> elements, where it controls the type of input control rendered.
HTML forms have built-in constraint validation that is enabled by default. When a user submits a form, the browser automatically checks inputs against their constraints (such as required, type="email", pattern, min, max, etc.) and prevents submission if any validation fails. There is no need to add a validate attribute to opt into this behavior because it is the default.
The HTML specification defines novalidate as a valid boolean attribute on the <form> element to disable this default validation, but it does not define a corresponding validate attribute. Using validate will trigger a W3C validation error because the browser doesn't recognize it and will simply ignore it.
This matters for several reasons:
- Standards compliance: Invalid attributes make your HTML non-conforming, which can cause issues with automated testing and quality tools.
- Developer confusion: A
validateattribute suggests it's doing something functional, but it has no effect. Future maintainers may incorrectly believe it's enabling validation and be reluctant to remove it. - Accessibility and tooling: Screen readers and other assistive technologies rely on well-formed HTML. Unrecognized attributes can lead to unpredictable behavior in some user agents.
To fix this issue, determine your intent:
- If you want form validation enabled — simply remove the
validateattribute. Validation is on by default. - If you want form validation disabled — replace
validatewithnovalidate.
Examples
Incorrect: using the invalid validate attribute
<formvalidateaction="/submit">
<labelfor="email">Email:</label>
<inputtype="email"id="email"name="email"required>
<buttontype="submit">Submit</button>
</form>
This triggers the error: Attribute "validate" not allowed on element "form" at this point.
Correct: relying on default validation (attribute removed)
Since constraint validation is enabled by default, simply remove the invalid attribute:
<formaction="/submit">
<labelfor="email">Email:</label>
<inputtype="email"id="email"name="email"required>
<buttontype="submit">Submit</button>
</form>
The browser will automatically validate the email input — checking both the required constraint and that the value matches a valid email format — before allowing submission.
Correct: using novalidate to disable validation
If your intention is to disable built-in validation (for example, because you handle validation with JavaScript), use the novalidate attribute instead:
<formnovalidateaction="/submit">
<labelfor="city">City:</label>
<inputtype="text"id="city"name="city"required>
<buttontype="submit">Submit</button>
</form>
In this example, even though the input has the required attribute, the browser will not prevent form submission when the field is empty, because novalidate tells the browser to skip constraint validation on submission.
Using formnovalidate on a specific button
If you want validation enabled for normal submission but want to bypass it for a specific button (such as a "Save Draft" button), use the formnovalidate attribute on that button instead of disabling validation for the entire form:
<formaction="/submit">
<labelfor="name">Name:</label>
<inputtype="text"id="name"name="name"required>
<buttontype="submit">Submit</button>
<buttontype="submit"formnovalidateformaction="/save-draft">Save Draft</button>
</form>
The "Submit" button will enforce validation, while the "Save Draft" button will skip it. This approach gives you fine-grained control without needing an invalid attribute.
When you write an attribute with an equals sign, the HTML specification expects a value to follow — either quoted ("value") or unquoted. An attribute like style= or class= leaves the parser in an ambiguous state because the equals sign signals that a value is coming, but nothing is there. While browsers may attempt to recover from this error, their behavior is not guaranteed to be consistent, and the resulting interpretation may not match your intent.
This matters for several reasons. First, it produces invalid HTML that fails W3C validation, which can be a requirement for accessibility compliance and professional standards. Second, certain attributes like style, class, or id with missing values can cause unexpected behavior in CSS selectors or JavaScript DOM queries. Third, assistive technologies such as screen readers may misinterpret malformed attributes, potentially degrading the experience for users with disabilities.
There are a few ways to fix this issue depending on what you intended:
- Provide a value: Add the missing value in quotes after the equals sign (e.g.,
class="container"). - Use an empty string: If you intentionally want a blank value, explicitly use empty quotes (e.g.,
style=""). - Remove the attribute: If the attribute isn't needed, delete it entirely.
- Remove the equals sign: If the attribute is a boolean attribute like
disabledorhidden, it doesn't need an equals sign or a value at all.
Examples
Missing attribute value (invalid)
<!-- The style attribute has an equals sign but no value -->
<pstyle=>This paragraph has an invalid attribute.</p>
<!-- The class attribute is missing its value -->
<divclass=>Content here</div>
<!-- The id attribute has no value after the equals sign -->
<spanid=>Some text</span>
Providing a proper value (valid)
<!-- Correct: the style attribute has a value -->
<pstyle="color: blue;">This paragraph is styled correctly.</p>
<!-- Correct: the class attribute has a value -->
<divclass="wrapper">Content here</div>
Using an empty string explicitly (valid)
If you genuinely need the attribute present but with no meaningful value, use empty quotes. This is syntactically valid, though often unnecessary:
<pstyle="">This paragraph has an explicitly empty style.</p>
Boolean attributes without equals signs (valid)
Boolean attributes like disabled, hidden, and readonly don't require a value. If you accidentally wrote one of these with a trailing equals sign, simply remove it:
<!-- Invalid: equals sign with no value -->
<buttondisabled=>Submit</button>
<!-- Valid: boolean attribute with no equals sign -->
<buttondisabled>Submit</button>
Common mistake with dynamic templates
This error frequently appears when a templating engine or framework outputs an attribute with a missing or null value. For example, server-rendered HTML might produce:
<!-- A template rendered an empty value -->
<ahref=>Click here</a>
The fix is to ensure your template logic provides a valid value or omits the attribute entirely:
<ahref="https://example.com">Click here</a>
Namespace declarations like xmlns:dc on an <svg> element are not serializable as XML 1.0 when used in an HTML5 document.
In HTML5 (the text/html serialization), namespace declarations using the xmlns: prefix syntax are not valid attributes. The HTML parser does not treat these as actual XML namespace declarations — it sees them as regular attributes with a colon in the name, which cannot be serialized back to well-formed XML 1.0. This commonly happens when SVG code is exported from graphic editors like Inkscape or Adobe Illustrator, which include Dublin Core (dc), RDF, and other XML namespace declarations that are unnecessary for rendering.
The SVG will render perfectly fine in browsers without these namespace prefixes. If the <svg> element doesn't actually use any elements or attributes from those namespaces (like <dc:title>), you can safely remove them. If it does contain such elements, those elements are also typically unused by browsers and can be removed as well.
Invalid Example
<svgxmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
viewBox="0 0 100 100">
<metadata>
<rdf:RDF>
<rdf:Descriptionrdf:about="">
<dc:title>My Icon</dc:title>
</rdf:Description>
</rdf:RDF>
</metadata>
<circlecx="50"cy="50"r="40"fill="blue"/>
</svg>
Valid Example
Remove the namespace declarations and any associated metadata elements:
<svgviewBox="0 0 100 100">
<circlecx="50"cy="50"r="40"fill="blue"/>
</svg>
If you still want to provide a title for accessibility, use the standard SVG <title> element instead:
<svgviewBox="0 0 100 100"role="img">
<title>My Icon</title>
<circlecx="50"cy="50"r="40"fill="blue"/>
</svg>
In XML-based formats like XHTML 1.0 or other XML vocabularies, namespace declarations such as xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" were used to associate element or attribute prefixes with specific namespace URIs. This allowed different XML vocabularies to coexist in a single document without naming conflicts. The xmlns:dt namespace in particular was commonly associated with Microsoft's XML data types, often seen in legacy ASP or older Microsoft-generated HTML.
HTML5, however, does not use the XML namespace mechanism. The HTML parser treats the document as HTML, not XML, and does not recognize or process custom namespace prefixes. The only xmlns-related attributes permitted in HTML5 are:
xmlnson the<html>element, but only with the valuehttp://www.w3.org/1999/xhtml(for compatibility with XHTML-serving scenarios).- Implicit namespace handling for embedded
<svg>and<math>elements, which the HTML parser manages automatically.
Any other xmlns:* attribute — such as xmlns:dt, xmlns:o, xmlns:v, or xmlns:st1 — is invalid in HTML5 and will trigger the W3C validator error: "Attribute with the local name 'xmlns:dt' is not serializable as XML 1.0."
Why this is a problem
- Standards compliance: Custom XML namespace attributes violate the HTML5 specification. The HTML parser does not process them, so they serve no functional purpose.
- Serialization issues: If the document is ever round-tripped through an XML serializer (for example, when converting HTML to XHTML), these attributes cannot be properly serialized under XML 1.0 rules, potentially causing parsing failures.
- Legacy baggage: These attributes typically appear in documents generated by older tools (such as Microsoft Word's "Save as HTML" feature) and carry over data-type or Office-specific namespace declarations that are meaningless in a modern web context.
- Document bloat: Keeping unused namespace declarations adds unnecessary bytes to your document without any benefit.
How to fix it
- Search your HTML for any attributes starting with
xmlns:on the<html>element or elsewhere in the document. - Remove them entirely. If your code relied on XML data types or Office-specific features tied to these namespaces, you'll need to refactor that logic using standard HTML5 attributes (such as
data-*attributes) or JavaScript. - Ensure your document uses a standard HTML5
<!DOCTYPE html>declaration and a clean<html>tag.
If you're working with content pasted from Microsoft Word or similar tools, consider running it through an HTML cleaner to strip out all Office-specific markup.
Examples
Incorrect — custom xmlns:dt attribute
This triggers the validation error because xmlns:dt is not a valid attribute in HTML5:
<htmlxmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello world</p>
</body>
</html>
Incorrect — multiple custom namespace declarations
Documents exported from older tools often include several invalid namespace attributes at once:
<htmlxmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello world</p>
</body>
</html>
Correct — clean HTML5 document
Remove all custom xmlns:* attributes and use a standard HTML5 structure:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello world</p>
</body>
</html>
Correct — using data attributes as a replacement
If you previously relied on namespace-prefixed attributes to store custom data on elements, use data-* attributes instead:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<pdata-type="datetime">2024-01-15</p>
</body>
</html>
Understanding the Issue
In the early days of the Open Graph Protocol (used by Facebook, LinkedIn, and other platforms to parse shared links), developers were instructed to add XML namespace declarations like xmlns:og and xmlns:fb to the <html> element. This was borrowed from XHTML conventions where custom prefixed attributes required namespace bindings.
However, modern HTML5 documents are not XML. The HTML5 parser does not support arbitrary namespace declarations in the way XHTML/XML does. Attributes with colons in their local names (like xmlns:og) are not serializable as XML 1.0, meaning they cannot be reliably round-tripped between HTML and XML parsers. The W3C validator flags this because these attributes violate the HTML serialization rules.
The good news is that these namespace declarations have never been required for Open Graph tags to work. Social media crawlers (Facebook's, Twitter's, LinkedIn's, etc.) parse <meta> tags based on the property attribute value directly — they don't rely on XML namespace resolution. Browsers also ignore these attributes entirely, so removing them has zero impact on functionality.
How to Fix It
- Locate your
<html>opening tag. - Remove any
xmlns:og,xmlns:fb, or similar namespace attributes. - Keep your Open Graph
<meta>tags exactly as they are — they will continue to work.
Examples
❌ Incorrect: Namespace attributes on the <html> element
<!DOCTYPE html>
<htmllang="en"xmlns:og="http://ogp.me/ns#"xmlns:fb="http://www.facebook.com/2008/fbml">
<head>
<title>My Page</title>
<metaproperty="og:title"content="My Page Title">
<metaproperty="og:description"content="A description of my page.">
<metaproperty="og:image"content="https://example.com/image.jpg">
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
This triggers the validator warning: Attribute with the local name "xmlns:og" is not serializable as XML 1.0 (and similarly for xmlns:fb).
✅ Correct: Clean <html> element without namespace attributes
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<metaproperty="og:title"content="My Page Title">
<metaproperty="og:description"content="A description of my page.">
<metaproperty="og:image"content="https://example.com/image.jpg">
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The Open Graph <meta> tags remain unchanged and will continue to be recognized by Facebook, LinkedIn, and all other platforms that support the Open Graph Protocol. The only change is removing the unnecessary xmlns:og and xmlns:fb attributes from the <html> tag.
Common Variations
You may also encounter other namespace prefixes like xmlns:article, xmlns:product, or xmlns:music. These are all unnecessary in HTML5 and should be removed:
<!-- ❌ Remove all of these -->
<htmllang="en"xmlns:og="http://ogp.me/ns#"xmlns:article="http://ogp.me/ns/article#"xmlns:fb="http://www.facebook.com/2008/fbml">
<!-- ✅ Keep it simple -->
<htmllang="en">
Note that the standard xmlns attribute (without a colon prefix) is allowed on the <html> element in HTML5 if its value is exactly http://www.w3.org/1999/xhtml. However, even this is unnecessary and can be omitted. The prefixed forms like xmlns:og are never valid in HTML5.
Namespaced attributes like xmlns:inkscape are not valid in HTML5 documents and should be removed from inline SVGs.
When you copy an SVG directly from editors like Inkscape or Adobe Illustrator, the markup often includes custom namespace declarations such as xmlns:inkscape or xmlns:sodipodi. These namespaces are used internally by the editor to store metadata like layer names, version info, and other tool-specific data.
In an HTML5 document, the HTML parser only recognizes a limited set of namespaces — specifically xmlns, xmlns:xlink, and the default SVG namespace. Any other namespaced attributes are not serializable as XML 1.0, which triggers this validation error.
The fix is straightforward: remove the editor-specific namespace declarations and any attributes that use those prefixes (e.g., inkscape:version, sodipodi:docname). These attributes serve no purpose in the browser and are safe to delete.
HTML Examples
❌ Invalid: editor-specific namespaces in inline SVG
<svgxmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.0.dtd"
inkscape:version="1.3"
sodipodi:docname="icon.svg"
width="100"height="100"viewBox="0 0 100 100">
<circlecx="50"cy="50"r="40"fill="blue"/>
</svg>
✅ Valid: clean inline SVG without editor namespaces
<svgxmlns="http://www.w3.org/2000/svg"
width="100"height="100"viewBox="0 0 100 100">
<circlecx="50"cy="50"r="40"fill="blue"/>
</svg>
Most SVG optimization tools like SVGO or Jake Archibald's SVGOMG will automatically strip these editor-specific namespaces and attributes for you.
The W3C HTML Validator raises this error when it encounters a namespaced attribute such as xmlns:m, xmlns:o, xmlns:v, or any other xmlns:* declaration in an HTML document. These prefixed namespace bindings are an XML concept defined in the XML Namespaces specification. In the HTML syntax (documents served with the text/html MIME type), the HTML parser does not treat these as namespace declarations — it treats them as regular attributes with a colon in the name. Because such attribute names are not serializable in XML 1.0, the validator reports the error.
This issue is extremely common with content exported from Microsoft Office (Word, Excel, PowerPoint). When you save or copy Office content as HTML, the generated markup often includes namespace declarations like xmlns:m (Office Math Markup Language), xmlns:o (Office namespace), xmlns:v (VML), and xmlns:w (Word-specific markup). These declarations were designed for older, XML-based HTML rendering and serve no purpose in modern HTML5 documents.
Why This Is a Problem
- Standards compliance: The HTML5 specification only permits the
xmlnsattribute (without a prefix) on the<html>element, and only with the valuehttp://www.w3.org/1999/xhtml. Prefixed forms likexmlns:mare not allowed. - Serialization: If a tool attempts to serialize the DOM as XML (for example,
XMLSerializer), attributes with colons that aren't properly bound namespaces can cause failures or unexpected output. - No functional benefit: In an HTML document, the browser's HTML parser ignores these namespace bindings. They don't enable any special behavior — they're dead weight in your markup.
- Maintainability: Leaving Office-generated namespace clutter in your HTML makes the code harder to read and maintain.
How to Fix It
- Remove the
xmlns:*attribute from your HTML element (or whichever element it appears on). In most cases, this is all you need to do — the namespaced content from Office isn't rendered by browsers anyway. - Clean up Office-generated HTML by stripping out all proprietary namespaces, conditional comments, and Office-specific elements. Tools like HTML Tidy or your editor's "paste as plain text" feature can help.
- Use native HTML5 equivalents where possible. HTML5 natively supports MathML and SVG without requiring explicit namespace declarations.
- Switch to XHTML only if you have a genuine need for XML namespaces. This means serving the document with the
application/xhtml+xmlMIME type and using well-formed XML syntax throughout.
Examples
Incorrect: Office-generated namespace declarations
This markup, typical of content exported from Microsoft Word, triggers the validation error:
<!DOCTYPE html>
<htmlxmlns:m="http://schemas.microsoft.com/office/2004/12/omml"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<title>Office Export</title>
</head>
<body>
<p>Content from Word</p>
</body>
</html>
Correct: Clean HTML5 without namespace declarations
Remove all xmlns:* attributes and any associated Office-specific markup:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>Office Export</title>
</head>
<body>
<p>Content from Word</p>
</body>
</html>
Incorrect: Single namespace on a non-html element
The error can also appear on other elements if a tool inserts namespace attributes:
<divxmlns:custom="http://example.com/ns">
<p>Some content</p>
</div>
Correct: Remove the namespace attribute
<div>
<p>Some content</p>
</div>
Using MathML natively in HTML5
If the xmlns:m attribute was added to support math content, note that HTML5 supports MathML directly without any namespace declaration:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>MathML in HTML5</title>
</head>
<body>
<p>The quadratic formula:</p>
<math>
<mi>x</mi>
<mo>=</mo>
<mfrac>
<mrow>
<mo>-</mo>
<mi>b</mi>
<mo>±</mo>
<msqrt>
<msup><mi>b</mi><mn>2</mn></msup>
<mo>-</mo>
<mn>4</mn><mi>a</mi><mi>c</mi>
</msqrt>
</mrow>
<mrow>
<mn>2</mn><mi>a</mi>
</mrow>
</mfrac>
</math>
</body>
</html>
No xmlns:m attribute is needed — the browser recognizes <math> as MathML automatically.
The W3C HTML Validator raises this error because HTML5 does not support arbitrary XML namespace declarations. In XML, the xmlns: prefix is used to bind namespace prefixes to URIs, allowing elements and attributes from different vocabularies to coexist. However, HTML5 uses its own parsing rules that are distinct from XML, and the only namespace attribute recognized in HTML5 is the plain xmlns attribute on the <html> element (set to http://www.w3.org/1999/xhtml). Colonized namespace attributes like xmlns:o, xmlns:v, xmlns:w, and others are not part of the HTML5 specification.
The xmlns:o="urn:schemas-microsoft-com:office:office" namespace specifically comes from Microsoft Office. When you save a Word document as HTML or copy-paste content from Office applications into an HTML editor, Office injects its own namespace declarations and proprietary markup. This markup is intended for round-tripping the document back into Office and serves no purpose on the web.
Beyond validation, leaving these attributes in place can cause practical problems. The HTML5 parser in browsers silently ignores or misinterprets these namespace declarations, meaning they add dead weight to your markup. They also increase file size unnecessarily and can confuse other tools that process your HTML, such as screen readers, search engine crawlers, or content management systems.
How to Fix
- Remove the
xmlns:oattribute from any element where it appears (typically the<html>tag). - Remove related Office namespace attributes such as
xmlns:v,xmlns:w,xmlns:x, andxmlns:st1, as these will trigger similar errors. - Remove any elements or attributes using those namespace prefixes, such as
<o:p>,<v:shape>, or<w:wrap>, since they are not valid HTML5 elements and browsers do not render them meaningfully. - Clean up Office-generated HTML thoroughly if you're converting Word documents to web content. Consider using a dedicated HTML cleaning tool or a paste-as-plain-text option in your editor.
Examples
Incorrect: Office namespace attributes on the <html> element
This markup contains multiple Microsoft Office namespace declarations that trigger validation errors:
<!DOCTYPE html>
<htmlxmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<title>My Document</title>
</head>
<body>
<h1>Meeting Notes</h1>
<p>Welcome to the meeting.<o:p></o:p></p>
</body>
</html>
Correct: Clean HTML5 without Office namespaces
Remove all xmlns: prefixed attributes and any Office-specific elements like <o:p>:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Document</title>
</head>
<body>
<h1>Meeting Notes</h1>
<p>Welcome to the meeting.</p>
</body>
</html>
Incorrect: Office namespace on a non-root element
Sometimes Office markup appears deeper in the document:
<divxmlns:o="urn:schemas-microsoft-com:office:office">
<p>Some content<o:p></o:p></p>
</div>
Correct: Cleaned-up version
<div>
<p>Some content</p>
</div>
By stripping out all Microsoft Office namespace declarations and their associated proprietary elements, your HTML becomes standards-compliant, lighter, and more compatible across browsers and assistive technologies. If you frequently convert Office documents to HTML, consider using a cleanup tool like DirtyMarkup or the "Paste as plain text" feature in your content editor to avoid these issues from the start.
Custom namespace declarations like xmlns:rdf are not serializable as XML 1.0 when used inside HTML5 documents.
In HTML5 (the text/html serialization), the xmlns attribute is only supported in a very limited way. You can use xmlns to declare the default namespace on the <html> or <svg> element, but you cannot declare additional namespace prefixes like xmlns:rdf, xmlns:dc, or xmlns:cc. These prefixed namespace declarations are a feature of XML and XHTML, and the HTML5 parser simply treats them as regular attributes — which then fail XML 1.0 serialization rules.
This commonly happens when SVG files are exported from tools like Inkscape, which embed RDF metadata with namespace declarations. When you paste or include such SVGs directly in an HTML5 document, the validator flags these attributes.
The fix is straightforward: remove the unsupported namespace declarations and any elements that depend on them. If the SVG contains <rdf:RDF>, <cc:Work>, or <dc:title> blocks, those can be safely removed without affecting the visual rendering of the SVG.
HTML Examples
❌ Invalid: SVG with unsupported namespace declarations
<svgxmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
viewBox="0 0 100 100">
<metadata>
<rdf:RDF>
<cc:Workrdf:about="">
<dc:title>My Icon</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<circlecx="50"cy="50"r="40"fill="blue"/>
</svg>
✅ Valid: SVG with namespace declarations and metadata removed
<svgviewBox="0 0 100 100">
<circlecx="50"cy="50"r="40"fill="blue"/>
</svg>
If you need to preserve metadata, consider adding it outside the SVG using standard HTML elements like <meta> tags or structured data formats such as JSON-LD.
When graphic design tools like Affinity Designer (formerly Serif) export SVG files, they often embed custom namespace declarations such as xmlns:serif="http://www.serif.com/". These namespaces allow the editor to store its own metadata — like layer names, grouping information, or application-specific settings — inside the SVG file. While this metadata is useful if you re-open the file in the original editor, it has no meaning in a web browser.
The HTML5 specification defines a specific set of namespace attributes that are allowed in SVG elements (such as xmlns, xmlns:xlink, and xmlns:xml). Any namespace prefix not in this predefined list — like xmlns:serif, xmlns:inkscape, or xmlns:sodipodi — triggers this validation error because the HTML parser cannot serialize these attributes back into well-formed XML 1.0. This isn't just a theoretical concern: non-serializable attributes can cause issues when the DOM is manipulated via JavaScript or when the markup is processed by XML-based tools.
Beyond the xmlns:serif declaration itself, you'll likely find attributes in the SVG that use this namespace prefix, such as serif:id="layer1". These should also be removed since they reference a namespace the browser doesn't understand.
How to Fix It
- Remove the
xmlns:serifattribute from the<svg>element. - Remove any attributes prefixed with
serif:(e.g.,serif:id) from child elements within the SVG. - If you re-export the SVG, check your editor's export settings — some tools offer a "clean" or "optimized" export option that strips proprietary metadata.
- Consider using an SVG optimization tool like SVGO to automatically clean up unnecessary attributes.
Examples
❌ Invalid: SVG with xmlns:serif attribute
<svgxmlns="http://www.w3.org/2000/svg"
xmlns:serif="http://www.serif.com/"
viewBox="0 0 100 100"
width="100"
height="100">
<gserif:id="Layer 1">
<circlecx="50"cy="50"r="40"fill="blue"/>
</g>
</svg>
This triggers the error because xmlns:serif is not a recognized namespace in HTML5, and serif:id references that unsupported namespace.
✅ Valid: SVG with proprietary attributes removed
<svgxmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100"
width="100"
height="100">
<g>
<circlecx="50"cy="50"r="40"fill="blue"/>
</g>
</svg>
Both xmlns:serif and serif:id have been removed. The SVG renders identically in the browser since those attributes were only meaningful to the editing application.
Handling Multiple Proprietary Namespaces
Exported SVGs sometimes contain several non-standard namespaces at once. Remove all of them:
<!-- ❌ Invalid: multiple proprietary namespaces -->
<svgxmlns="http://www.w3.org/2000/svg"
xmlns:serif="http://www.serif.com/"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 200 200">
<rectx="10"y="10"width="180"height="180"fill="red"
serif:id="background"
inkscape:label="bg-rect"/>
</svg>
<!-- ✅ Valid: all proprietary namespaces and prefixed attributes removed -->
<svgxmlns="http://www.w3.org/2000/svg"
viewBox="0 0 200 200">
<rectx="10"y="10"width="180"height="180"fill="red"/>
</svg>
If you frequently work with SVGs from design tools, integrating an SVG optimizer into your build process can save time and ensure these non-standard attributes never reach production.
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