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 vertical-align property controls the vertical positioning of inline-level elements (like <span>, <img>, and <a>) and table-cell elements (<td>, <th>) relative to their surrounding content or cell. Unlike some other CSS properties (such as float or border), vertical-align has no none keyword. Attempting to use none results in an invalid declaration that browsers will ignore, meaning the element will fall back to the default value of baseline.
This mistake often happens when a developer wants to "reset" or "remove" vertical alignment. Since there is no none value, the correct approach is to either set vertical-align: baseline (the initial value) or remove the vertical-align declaration altogether.
The valid keyword values for vertical-align are:
baseline— aligns the element's baseline with the parent's baseline (default)sub— aligns as a subscriptsuper— aligns as a superscripttext-top— aligns with the top of the parent's fonttext-bottom— aligns with the bottom of the parent's fontmiddle— aligns the middle of the element with the baseline plus half the x-height of the parenttop— aligns the top of the element with the top of the tallest element on the linebottom— aligns the bottom of the element with the bottom of the lowest element on the line
In addition to keywords, vertical-align also accepts length values (e.g., 5px, 0.5em) and percentage values (e.g., 50%), which offset the element relative to the baseline.
Using an invalid value like none causes a W3C validation error and means your intended styling is silently ignored by the browser. This can lead to unexpected layout results that are difficult to debug, especially in table layouts or inline formatting contexts where vertical alignment significantly affects appearance.
Examples
❌ Invalid: using none
<p>
Text with an <img src="icon.png" alt="icon" style="vertical-align: none;"> inline image.
</p>
The validator will report that none is not a valid vertical-align value. The browser ignores the declaration and defaults to baseline.
✅ Fixed: using a valid keyword
If you want the image vertically centered with the text, use middle:
<p>
Text with an <img src="icon.png" alt="icon" style="vertical-align: middle;"> inline image.
</p>
✅ Fixed: resetting to the default
If your intent was to "remove" any vertical alignment, use baseline (the initial value) or simply remove the property:
<p>
Text with an <img src="icon.png" alt="icon" style="vertical-align: baseline;"> inline image.
</p>
❌ Invalid: none in a stylesheet for table cells
<style>
td.reset {
vertical-align: none;
}
</style>
<table>
<tr>
<td class="reset">Cell content</td>
</tr>
</table>
✅ Fixed: valid value for table cells
For table cells, the default vertical-align value is middle in most browsers. To explicitly reset it or set a specific alignment:
<style>
td.top-aligned {
vertical-align: top;
}
</style>
<table>
<tr>
<td class="top-aligned">Cell content</td>
</tr>
</table>
✅ Fixed: using a length value
You can also use a specific length to offset the element from the baseline:
<p>
Text with a <span style="vertical-align: 4px;">slightly raised</span> word.
</p>
Choose the value that matches your design intent — baseline to reset, middle or top for common alignment needs, or a specific length or percentage for precise control.
An invalid value was assigned to the CSS visibility property inside your HTML document.
The visibility property controls whether an element is visually displayed without affecting the document layout. Unlike display: none, a hidden element still occupies space on the page.
The accepted values for visibility are:
visible— the element is shown (default).hidden— the element is invisible but still takes up space.collapse— used primarily with table rows and columns to remove them without affecting the table layout. On non-table elements, it behaves likehidden.
This error typically occurs when you use a value meant for a different property, such as none (which belongs to display), or a misspelled value like hiden or visble.
Invalid Example
<p style="visibility: none;">This text is hidden.</p>
The value none is not valid for visibility. You likely meant hidden or intended to use the display property instead.
Fixed Example
Using the correct visibility value:
<p style="visibility: hidden;">This text is hidden but still takes up space.</p>
Or, if you want the element to be fully removed from the layout, use display instead:
<p style="display: none;">This text is completely removed from the layout.</p>
The white-space property is a shorthand that combines the behavior of white-space-collapse and text-wrap-mode. When you use a value that doesn't match any of the accepted keywords — whether due to a typo, a made-up value, or a value that belongs to a different CSS property — the W3C validator flags it as invalid. This commonly happens when authors confuse values from related properties (like using break-spaces where it isn't supported in inline styles being validated, or misspelling nowrap as no-wrap).
Using invalid CSS values means browsers will ignore the declaration entirely, falling back to the default behavior (white-space: normal). This can cause unexpected text wrapping or whitespace collapsing that breaks your layout. Keeping your CSS valid ensures consistent rendering across browsers and makes your stylesheets easier to maintain and debug.
The accepted values for white-space are:
normal— Collapses whitespace sequences, wraps text as needed (default).nowrap— Collapses whitespace but suppresses line breaks; text won't wrap.pre— Preserves whitespace and line breaks exactly as written, like the<pre>element.pre-wrap— Preserves whitespace and line breaks, but also allows text to wrap when necessary.pre-line— Collapses whitespace sequences into a single space, but preserves explicit line breaks and allows wrapping.break-spaces— Similar topre-wrap, but trailing spaces and spaces at the end of lines don't hang and do affect box sizing.
Additionally, CSS Text Level 4 introduced shorthand combinations using white-space-collapse and text-wrap-mode keywords, such as collapse, preserve, wrap, and preserve nowrap. However, support for these newer shorthand forms varies, and older validators or browsers may not recognize them.
Global CSS values (inherit, initial, revert, revert-layer, unset) are also valid.
Examples
Incorrect: invalid value triggers the error
A common mistake is using no-wrap (with a hyphen) instead of the correct nowrap:
<p style="white-space: no-wrap;">This text should not wrap.</p>
Another common mistake is using a value from a different property entirely:
<p style="white-space: hidden;">This text has an invalid white-space value.</p>
Correct: using valid white-space values
<p style="white-space: nowrap;">This text will not wrap to a new line.</p>
<p style="white-space: pre-wrap;">This text preserves whitespace
and line breaks, but also wraps when needed.</p>
<p style="white-space: pre-line;">This collapses extra spaces
but preserves explicit line breaks.</p>
Correct: using the property in a <style> block
<!DOCTYPE html>
<html lang="en">
<head>
<title>White-space example</title>
<style>
.no-wrap {
white-space: nowrap;
}
.preserve {
white-space: pre-wrap;
}
</style>
</head>
<body>
<p class="no-wrap">This long paragraph will stay on a single line without wrapping.</p>
<p class="preserve">This preserves multiple spaces
and line breaks exactly as written.</p>
</body>
</html>
If you encounter this validation error, double-check your white-space value for typos and confirm it matches one of the recognized keywords listed above.
This error originates from CSS validation, not HTML element validation. It typically appears when the validator encounters a width value in a style attribute or <style> block that doesn't conform to the CSS specification for the width property. The CSS width property accepts <length>, <percentage>, auto, min-content, max-content, fit-content, or fit-content(<length-percentage>) values. Anything outside these types—or an expression that produces an incompatible type—will trigger this error.
Common causes include:
- Missing units on a numeric value. In CSS,
width: 400is invalid (unlike the HTMLwidthattribute on elements like<img>, which expects a unitless integer). CSS requires a unit such aspx,em,rem,%,vw, etc., unless the value is0. - Invalid
calc()expressions. For example,calc(100% - 20)is invalid because100%is a percentage and20has no unit—you cannot subtract a unitless number from a percentage. It should becalc(100% - 20px). - Typos or unrecognized values. Things like
width: 50 px(space between number and unit),width: autopx, orwidth: 100pixelsare not valid CSS. - Using HTML attribute syntax in CSS. Writing
width: 400in a stylesheet because you're used to writing<img width="400">in HTML.
This matters for standards compliance and cross-browser reliability. While some browsers may attempt to interpret invalid values, the behavior is undefined and inconsistent. Relying on invalid CSS can lead to broken layouts in certain browsers or future browser versions.
How to Fix It
- Add proper units to any bare numeric
widthvalue in your CSS. Usepx,em,rem,%,vw, or another valid CSS length unit. - Check
calc()expressions to ensure both sides of addition or subtraction are compatible types (e.g., length with length, or percentage with length—both are valid incalc()). Unitless numbers (other than0) cannot be mixed with lengths or percentages in addition/subtraction. - Remove spaces between numbers and their units.
50pxis valid;50 pxis not. - Use valid keywords only:
auto,min-content,max-content,fit-content.
Examples
Incorrect: Missing unit in inline style
<div style="width: 400;">Content</div>
Correct: Adding a proper unit
<div style="width: 400px;">Content</div>
Incorrect: Incompatible types in calc()
<div style="width: calc(100% - 20);">Content</div>
The value 20 has no unit, so it cannot be subtracted from a percentage.
Correct: Compatible types in calc()
<div style="width: calc(100% - 20px);">Content</div>
Incorrect: Space between number and unit
<p style="width: 50 %;">Some text</p>
Correct: No space between number and unit
<p style="width: 50%;">Some text</p>
Incorrect: Unitless number in a <style> block
<!DOCTYPE html>
<html lang="en">
<head>
<title>Example</title>
<style>
.sidebar {
width: 300;
}
</style>
</head>
<body>
<aside class="sidebar">Sidebar content</aside>
</body>
</html>
Correct: Valid length value in a <style> block
<!DOCTYPE html>
<html lang="en">
<head>
<title>Example</title>
<style>
.sidebar {
width: 300px;
}
</style>
</head>
<body>
<aside class="sidebar">Sidebar content</aside>
</body>
</html>
Note on the HTML width attribute
Don't confuse CSS width with the HTML width attribute. The HTML width attribute on elements like <img>, <video>, and <canvas> expects a unitless integer:
<img src="photo.jpg" width="400" alt="A sample photo">
Writing width="400px" in an HTML attribute is a separate validation error. The CSS error discussed in this guide specifically concerns width values in stylesheets or style attributes where a valid CSS length is required.
The CSS width property sets an element's width and accepts a single value. The W3C validator reports this error when it encounters something it cannot parse as a valid width declaration. Common causes include:
- Missing units: Writing
width: 300instead ofwidth: 300px. CSS requires explicit units for non-zero lengths. - Multiple values: Writing
width: 100px 200pxas ifwidthaccepted shorthand-style multiple values (it doesn't). - Typos or invalid keywords: Writing
width: auotinstead ofwidth: auto, or using a made-up keyword. - Invalid functions or syntax: Using incorrect function syntax like
width: calc(100% - 20px)with missing spaces around operators, or using browser-prefixed values without a standard fallback. - Unsupported values: Using newer CSS values like
fit-contentormax-contentin a context where the validator's CSS level doesn't recognize them.
This matters because invalid CSS can cause browsers to silently discard the entire declaration, meaning your intended layout won't be applied. Different browsers may handle invalid values differently, leading to inconsistent rendering. Keeping your CSS valid ensures predictable, cross-browser behavior.
Valid values for width
The width property accepts exactly one of the following:
- Length values: A number with a unit, such as
300px,25em,10rem,5vw. - Percentage values: A percentage relative to the containing block, such as
75%. - Keyword values:
auto,max-content,min-content,fit-content. - Function values:
fit-content(20em),calc(100% - 40px),min(300px, 100%),max(200px, 50%),clamp(200px, 50%, 600px). - Global values:
inherit,initial,revert,revert-layer,unset.
Note that 0 is the only numeric value that does not require a unit.
Examples
Incorrect: missing unit
<style>
.box {
width: 300;
}
</style>
<div class="box">Content</div>
A bare number (other than 0) is not valid. The browser won't know if you mean pixels, ems, or something else.
Correct: unit provided
<style>
.box {
width: 300px;
}
</style>
<div class="box">Content</div>
Incorrect: too many values
<style>
.sidebar {
width: 200px 400px;
}
</style>
<aside class="sidebar">Sidebar</aside>
Unlike properties such as margin or padding, width only accepts a single value.
Correct: single value
<style>
.sidebar {
width: 200px;
}
</style>
<aside class="sidebar">Sidebar</aside>
Incorrect: typo in keyword
<style>
.container {
width: auot;
}
</style>
<div class="container">Content</div>
Correct: proper keyword
<style>
.container {
width: auto;
}
</style>
<div class="container">Content</div>
Incorrect: malformed calc() expression
<style>
.panel {
width: calc(100%-40px);
}
</style>
<div class="panel">Content</div>
The calc() function requires spaces around + and - operators.
Correct: properly spaced calc() expression
<style>
.panel {
width: calc(100% - 40px);
}
</style>
<div class="panel">Content</div>
Incorrect: accidental semicolon or extra text
<style>
.card {
width: 50% important;
}
</style>
<div class="card">Content</div>
If you intended to use !important, the ! is required.
Correct: proper !important syntax
<style>
.card {
width: 50% !important;
}
</style>
<div class="card">Content</div>
The CSS width property contains an invalid value.
The width property accepts specific types of values: lengths (like 100px, 10em, 5rem), percentages (50%), viewport units (100vw), the keyword auto, and sizing keywords like max-content, min-content, or fit-content. The validator rejects anything that doesn't match these formats.
Common mistakes that trigger this error:
- Missing a unit:
width: 100instead ofwidth: 100px. Plain numbers (other than0) are not valid CSS lengths. - Using an invalid unit or typo:
width: 100 px(with a space),width: 100ppx. - Passing a non-length value:
width: red,width: bold,width: none. The keywordnoneworks formax-widthbut not forwidth. - Including extra characters:
width: 100px;50pxorwidth: 100px !importnt.
Invalid example
<div style="width: 600">
<p>This box has no unit on its width value.</p>
</div>
The value 600 is not valid because it lacks a CSS unit.
Fixed example
<div style="width: 600px">
<p>This box now has a valid width.</p>
</div>
Adding px (or another appropriate unit like em, %, rem, vw) makes the value valid. If the intent is to let the element size itself naturally, use width: auto instead.
This is an internal error from the W3C validator's CSS checking engine (the Jigsaw CSS validator). The message Cannot invoke "org.w3c.css.values.CssValue.getType()" because "Y" is null is a Java NullPointerException surfacing from the validator's source code. In practical terms, it means the validator tried to determine the type of a CSS value, but that value didn't exist or couldn't be computed.
There are several common causes for this error:
- Malformed or incomplete CSS values — A property is missing part of its value, such as a shorthand with too few components, or a function with missing arguments.
- Unsupported CSS features — Newer CSS features or non-standard syntax that the validator's CSS engine doesn't fully support can trigger internal failures rather than clean error messages.
- Invalid value combinations — Using values together in a way that doesn't match any known CSS grammar rule can cause the parser to fail unexpectedly.
- Syntax errors in custom properties or functions — Mistakes inside
calc(),var(), or other CSS functions can sometimes cause this kind of crash in the validator.
While this error technically originates from the validator itself (and could be considered a validator bug), it almost always points to CSS that is non-standard, malformed, or pushing the boundaries of what the validator can parse. Fixing the underlying CSS issue resolves the error.
How to Fix It
- Locate the CSS property referenced in the error — The
"X"in the error message identifies the CSS property or value that caused the failure. - Check for syntax errors — Look for missing values, unclosed parentheses, stray commas, or incomplete shorthand declarations.
- Simplify complex expressions — If you're using
calc(), nested functions, or complex shorthand values, try breaking them into simpler, longhand declarations. - Check for unsupported features — Some modern CSS (e.g., certain uses of
color-mix(), newer color syntaxes, or container query units) may not yet be supported by the validator. Consider whether validation of that specific rule is critical. - Validate CSS separately — Paste your CSS into the W3C CSS Validator directly to isolate the problematic rule.
Examples
Malformed shorthand value
A missing value in a shorthand property can trigger this internal error:
<div style="border: 1px solid;">Content</div>
The border shorthand here has a trailing space after solid with no color specified. While browsers handle this gracefully by using a default, the validator may fail to process the incomplete value. Fix it by providing all intended values explicitly:
<div style="border: 1px solid black;">Content</div>
Incomplete function syntax
Missing arguments inside CSS functions are another common trigger:
<style>
.box {
width: calc(100% - );
background-color: rgb(255, 128);
}
</style>
The calc() expression is missing its second operand, and rgb() is missing its third argument. Fix both by providing complete values:
<style>
.box {
width: calc(100% - 20px);
background-color: rgb(255, 128, 0);
}
</style>
Complex expressions the validator cannot parse
Sometimes valid, modern CSS triggers this error because the validator's engine doesn't fully support it:
<style>
.card {
background: color-mix(in srgb, #3498db 70%, transparent);
}
</style>
If this triggers the internal error, you can provide a fallback or simplify:
<style>
.card {
background: rgba(52, 152, 219, 0.7);
}
</style>
Accidental double values
A typo that results in two values where one is expected can also cause this:
<style>
.text {
font-size: 16px 14px;
}
</style>
Fix by providing only the single expected value:
<style>
.text {
font-size: 16px;
}
</style>
If you believe your CSS is correct and the validator is producing this error incorrectly, it may be a genuine bug in the validator. You can report it at the W3C CSS Validator's GitHub repository. In the meantime, check that your CSS works correctly across target browsers and consider adding a /* validated */ comment near the line so you can track intentional exceptions.
CSS uses semicolons as delimiters between declarations. When you forget one, the parser tries to interpret the next property name as part of the previous declaration's value. For example, if you write z-index: auto content: "", the parser reads auto content as if it were the value of z-index, which is invalid. It then encounters the colon after what it expected to be a value, resulting in a parsing error that can cause one or more of your declarations to be silently ignored.
This is a problem for several reasons:
- Broken styles: The browser will typically discard the malformed declaration and potentially subsequent ones, leading to unexpected visual results that can be difficult to debug.
- Standards compliance: The CSS specification requires semicolons between declarations. While the last declaration in a block technically doesn't need a trailing semicolon, omitting it is a common source of bugs when new declarations are added later.
- Maintainability: Always including semicolons — even on the last declaration — is a widely recommended best practice. It prevents this exact class of errors when code is edited or rearranged in the future.
To fix this issue, locate the line referenced in the error message and check the declaration immediately before it. Add the missing semicolon at the end of that declaration.
Examples
❌ Missing semicolon between declarations
The semicolon is missing after z-index: auto, so the parser cannot recognize content as a new property:
<style>
.overlay {
z-index: auto
content: "";
display: block;
}
</style>
✅ Fixed with semicolon added
Adding the semicolon after auto properly terminates the z-index declaration:
<style>
.overlay {
z-index: auto;
content: "";
display: block;
}
</style>
❌ Missing semicolon with shorthand properties
Shorthand values with multiple parts can make it harder to spot the missing semicolon:
<style>
.card {
margin: 10px 20px 10px 20px
padding: 1em;
border: 1px solid #ccc;
}
</style>
✅ Fixed shorthand example
<style>
.card {
margin: 10px 20px 10px 20px;
padding: 1em;
border: 1px solid #ccc;
}
</style>
❌ Missing semicolon on the last declaration causes issues when editing
While technically valid, omitting the trailing semicolon on the last declaration becomes a bug the moment a new line is added:
<style>
.button {
color: white;
background: blue
border-radius: 4px;
}
</style>
Here, background: blue was originally the last declaration (without a semicolon). When border-radius was added afterward, the missing semicolon was not noticed.
✅ Best practice: always include a trailing semicolon
<style>
.button {
color: white;
background: blue;
border-radius: 4px;
}
</style>
By consistently ending every declaration with a semicolon — including the last one in each rule block — you avoid this error entirely and make your stylesheets easier to maintain.
CSS math functions like calc(), min(), max(), and clamp() follow strict rules about how operands and operators interact. The error "one operand must be a number" most commonly fires in two scenarios: either an operand is missing entirely (e.g., calc(100% - )), or both operands in a multiplication or division carry units (e.g., calc(10px * 5px)). The CSS Values and Units specification requires that for * (multiplication), at least one side must be a unitless <number>. For / (division), the right-hand side must always be a unitless <number>. You cannot multiply two lengths together or divide a length by another length within calc().
This matters for several reasons. Browsers will discard the entire property declaration if the calc() expression is invalid, which can cause layout breakage or fallback to unexpected default values. The W3C validator catches these errors in inline style attributes and embedded <style> blocks, helping you identify expressions that will silently fail in production. Fixing these issues ensures predictable rendering across all browsers.
How the rules work
- Addition and subtraction (
+,-): Both operands must have compatible types (e.g., both lengths, or both percentages, or a mix of length and percentage). Both must be present. - Multiplication (
*): At least one operand must be a plain<number>(unitless). You can writecalc(10px * 3)orcalc(3 * 10px), but notcalc(10px * 5px). - Division (
/): The right-hand operand must be a plain<number>(unitless and non-zero). You can writecalc(100px / 2), but notcalc(100px / 2px).
Examples
Missing operand
A common mistake is leaving out a value on one side of an operator:
<!-- ❌ Wrong: missing operand after the minus sign -->
<div style="width: calc(100% - );"></div>
<!-- ✅ Fixed: both operands are present -->
<div style="width: calc(100% - 50px);"></div>
Multiplying two values with units
You cannot multiply two unit-bearing values together, because the result would be a meaningless type like "px²":
<!-- ❌ Wrong: both operands have units -->
<div style="width: calc(10px * 5px);"></div>
<!-- ✅ Fixed: one operand is a unitless number -->
<div style="width: calc(10px * 5);"></div>
Dividing by a value with units
The divisor in a / operation must be a unitless number:
<!-- ❌ Wrong: dividing by a value with units -->
<div style="height: calc(500px / 2em);"></div>
<!-- ✅ Fixed: divisor is a unitless number -->
<div style="height: calc(500px / 2);"></div>
Nested calc() with a missing value
Errors can hide inside nested expressions:
<!-- ❌ Wrong: inner calc has an incomplete expression -->
<p style="margin-top: calc(2rem + calc(100% * ));"></p>
<!-- ✅ Fixed: all operands are present and valid -->
<p style="margin-top: calc(2rem + calc(100% * 0.5));"></p>
Using variables or keywords where a number is expected
Sometimes a typo or misunderstanding leads to a non-numeric token where a number is required:
<!-- ❌ Wrong: "auto" is not a valid operand in calc() -->
<div style="width: calc(auto * 2);"></div>
<!-- ✅ Fixed: use a numeric value or percentage -->
<div style="width: calc(100% * 2);"></div>
To resolve this error, review every calc(), min(), max(), and clamp() expression in your inline styles and stylesheets. Confirm that all operators have valid operands on both sides, that * always has at least one unitless number, and that / always has a unitless number on the right. If you're building expressions dynamically (e.g., via JavaScript or a templating engine), double-check that variables are being interpolated correctly and not producing empty or invalid values.
When the W3C HTML Validator checks your document, it also validates any inline styles (in style attributes) and embedded stylesheets (in <style> elements). A CSS parse error occurs when the parser encounters something it cannot interpret according to CSS specifications. The "X" in the error message refers to the specific property, value, or token that triggered the failure.
Understanding CSS Parse Errors
CSS parse errors can stem from many different causes:
- Typos in property names or values — e.g.,
colrinstead ofcolor, or10xpinstead of10px. - Missing or extra punctuation — a forgotten semicolon, an extra colon, unmatched braces or parentheses.
- Invalid values for a property — using a value that doesn't belong to that property's grammar.
- Vendor-prefixed or non-standard syntax — properties like
-webkit-appearanceor-moz-osx-font-smoothingare not part of the CSS standard and will trigger parse errors in the validator. - Modern CSS features not yet recognized — some newer CSS syntax may not be supported by the validator's parser yet.
- Stray characters or encoding issues — invisible characters, smart quotes, or copy-paste artifacts from word processors.
While browsers are generally forgiving and will skip CSS they don't understand, parse errors can indicate real bugs that cause styles to silently fail. Fixing them ensures your CSS is standards-compliant and behaves predictably across all browsers.
Common Causes and Fixes
Typos and syntax mistakes
The most frequent cause is a simple typo or a missing character. Always double-check the exact line the validator points to.
Missing semicolons
A forgotten semicolon between declarations can cause the parser to misinterpret subsequent properties.
Invalid or malformed values
Using values that don't match the property's expected syntax — such as omitting units, using incorrect function syntax, or providing the wrong number of arguments — will trigger parse errors.
Vendor prefixes
The W3C validator checks against the CSS specification. Vendor-prefixed properties and values are non-standard and will produce parse errors. While you may still need them in production, be aware that these will always flag in validation.
Examples
❌ Missing semicolon between declarations
<p style="color: red background-color: blue;">Hello</p>
The missing semicolon after red causes the parser to try to interpret red background-color: blue as a single value, resulting in a parse error.
✅ Fixed: semicolons separating declarations
<p style="color: red; background-color: blue;">Hello</p>
❌ Typo in property name
<style>
.box {
widht: 100px;
hieght: 200px;
}
</style>
✅ Fixed: correct property names
<style>
.box {
width: 100px;
height: 200px;
}
</style>
❌ Missing unit on a value
<style>
.container {
margin: 10;
padding: 20px;
}
</style>
Numeric values (other than 0) require a unit. The value 10 without a unit like px, em, or rem is invalid.
✅ Fixed: unit included
<style>
.container {
margin: 10px;
padding: 20px;
}
</style>
❌ Extra or misplaced characters
<style>
.title {
font-size:: 16px;
color: #3333;
}
</style>
The double colon after font-size and the 4-digit hex color #3333 (which is valid in CSS Color Level 4 but may not be recognized by all validator parsers) can trigger errors.
✅ Fixed: correct syntax
<style>
.title {
font-size: 16px;
color: #333333;
}
</style>
❌ Unmatched parentheses in a function
<style>
.overlay {
background: rgba(0, 0, 0, 0.5;
}
</style>
✅ Fixed: closing parenthesis added
<style>
.overlay {
background: rgba(0, 0, 0, 0.5);
}
</style>
Tips for Debugging Parse Errors
- Read the error message carefully. The validator usually points to the specific token or line that caused the failure.
- Validate CSS separately. Use the W3C CSS Validation Service for more detailed CSS-specific error messages.
- Check for invisible characters. If you copied CSS from a word processor, PDF, or website, hidden characters like zero-width spaces or smart quotes (
"instead of") may be present. Retype the line manually if in doubt. - Simplify and isolate. If you can't find the error, remove declarations one at a time until the error disappears, then inspect the last removed declaration closely.
The validator flags any declaration where the property token doesn’t match a known CSS property in its ruleset. Common causes include typos, wrong hyphenation, using values where property names should go, properties from older drafts that were renamed, or relying solely on vendor-prefixed/experimental properties without a standard equivalent. It can also show up when copy-pasting snippets that include custom, nonstandard properties.
Why this matters:
- Browser compatibility: Unknown properties are ignored, causing styles to silently fail.
- Maintainability: Typos and nonstandard syntax make CSS harder to debug.
- Standards compliance: Clean, validated CSS reduces cross-browser surprises and eases future maintenance.
How to fix it:
- Check spelling and hyphenation exactly (e.g.,
text-decoration-skip-ink, nottext-decoration-skipink). - Verify the property exists on MDN or in the CSS specifications; if it’s not documented, it’s likely invalid.
- Replace deprecated or draft names with current standardized ones.
- If using experimental features, include a standard fallback and keep vendor-prefixed versions alongside the unprefixed property when supported.
- Remove framework- or tool-specific tokens that aren’t valid CSS at runtime.
- Don’t invent properties. If you need custom data for JS, use
data-*attributes in HTML, not fake CSS properties.
Examples
Example that triggers the error (typo) and the corrected version
Invalid:
<p style="colr: red;">Hello</p>
Valid:
<p style="color: red;">Hello</p>
Example using a deprecated/draft name replaced with the current property
Invalid (older draft name):
<div style="gap: 1rem; grid-row-gap: 8px;"></div>
Valid (current, standardized property):
<div style="row-gap: 8px; gap: 1rem;"></div>
Example with vendor-prefixed property plus standard fallback
Invalid (only vendor-prefixed, missing standard property):
<div style="-webkit-user-select: none;"></div>
Valid (fallback plus prefix):
<div style="user-select: none; -webkit-user-select: none;"></div>
Example removing a nonstandard custom property name misuse
Invalid (attempting to invent a property):
<div style="button-style: primary;"></div>
Valid (use classes and real CSS properties):
<style>
.btn--primary {
background-color: #0b5fff;
color: #fff;
}
</style>
<button class="btn--primary">Submit</button>
Example with custom properties (variables) used correctly
Valid use of CSS custom properties (won’t trigger the error because the property is standard and custom properties start with --):
<style>
:root {
--brand-color: #0b5fff;
}
.tag {
color: var(--brand-color);
}
</style>
<span class="tag">Tag</span>
Full document with corrected properties
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CSS Property Validation Fixes</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.card {
display: grid;
gap: 1rem;
row-gap: 0.5rem;
user-select: none;
-webkit-user-select: none;
color: #222;
}
</style>
</head>
<body>
<div class="card">Valid CSS properties in use</div>
</body>
</html>
Quick checklist:
- Confirm the property on MDN. If not found, it’s probably invalid.
- Fix spelling/casing; CSS properties are lowercase with hyphens.
- Prefer standardized names; keep prefixes only as supplements.
- Use CSS custom properties starting with
--if you need variables. - Remove tool-specific placeholders before validation.
Every CSS property has a defined value syntax that specifies exactly which values it accepts and how many. When the validator encounters a declaration that doesn't match this syntax, it flags the error. This can happen for several distinct reasons:
- Too many values: A property receives more values than its syntax allows. For example,
marginaccepts one to four values, so a fifth value is invalid. Thecolorproperty accepts only a single color value, so writing two colors is an error. - Unrecognized values: A keyword is misspelled (e.g.,
blockyinstead ofblock) or simply doesn't exist for that property (e.g.,color: bold). - Newer or non-standard values: A value that belongs to a draft specification, a vendor-prefixed feature, or a browser-specific extension may not be recognized by the validator.
- Missing separators or syntax errors: A missing comma in a multi-value function like
rgb()or a missing slash in shorthand likefontcan cause the parser to misinterpret the values.
This matters because browsers handle invalid CSS unpredictably — they typically discard the entire declaration, which means your intended styles silently disappear. Fixing these errors ensures your styles are applied consistently across browsers and makes your stylesheets easier to maintain and debug.
How to Fix
- Identify the property and value reported in the error message.
- Check spelling of every keyword. Common mistakes include
inheret(should beinherit),trasparent(should betransparent), andcentre(should becenter). - Count the values and compare against the property's specification. Consult MDN Web Docs for the accepted value syntax.
- Verify function syntax — ensure commas, slashes, and parentheses are correct in functions like
rgb(),calc(), andclamp(). - Check for unsupported modern syntax — if you're using newer CSS features, the validator may not recognize them yet. In that case, verify the syntax is correct per the spec and consider the warning informational.
Examples
Too many values for a property
The color property only accepts a single color value, and margin accepts at most four values:
<!-- ❌ Invalid: too many values -->
<p style="color: red blue;">Hello</p>
<p style="margin: 10px 20px 5px 0px 15px;">Hello</p>
<!-- ✅ Valid: correct number of values -->
<p style="color: red;">Hello</p>
<p style="margin: 10px 20px 5px 0px;">Hello</p>
Unrecognized keyword value
A typo or non-existent keyword triggers the error:
<!-- ❌ Invalid: "blocky" is not a valid display value -->
<div style="display: blocky;">Content</div>
<!-- ✅ Valid: correct keyword -->
<div style="display: block;">Content</div>
Misspelled value in a <style> block
<!-- ❌ Invalid -->
<style>
.box {
background-color: trasparent;
text-align: centre;
}
</style>
<!-- ✅ Valid -->
<style>
.box {
background-color: transparent;
text-align: center;
}
</style>
Incorrect function syntax
Missing commas or extra arguments inside CSS functions can also trigger this error:
<!-- ❌ Invalid: missing commas in rgb() -->
<p style="color: rgb(255 0 0 0.5);">Hello</p>
<!-- ✅ Valid: use the correct modern syntax with a slash for alpha -->
<p style="color: rgb(255 0 0 / 0.5);">Hello</p>
Shorthand property confusion
Shorthand properties like font and background have specific value order requirements. Providing values in the wrong order or mixing incompatible values causes errors:
<!-- ❌ Invalid: incorrect font shorthand -->
<style>
p {
font: bold Arial 16px;
}
</style>
<!-- ✅ Valid: size must come before family, weight before size -->
<style>
p {
font: bold 16px Arial;
}
</style>
When in doubt, break shorthand properties into their individual longhand properties (font-weight, font-size, font-family) to isolate which value the validator is rejecting.
In CSS, a "dimension" is a number immediately followed by a unit identifier — for example, 16px, 2em, or 100vh. When the validator encounters a dimension token with a unit it doesn't recognize, it flags it as an unknown dimension. The "X" in the error message is replaced with the actual unrecognized value, such as 10quux or 5pixels.
This issue commonly arises from:
- Typos in unit names — writing
10pxlinstead of10px, or2emsinstead of2em. - Made-up or non-standard units — using units that don't exist in any CSS specification.
- Missing spaces or operators — accidentally concatenating a number with a keyword, like
100vhmaxinstead of usingmax(100vh, ...). - Using units in the wrong context — some newer or less common units may not yet be recognized by the validator, though all widely supported CSS units should be accepted.
This matters because browsers may silently ignore or misinterpret properties with invalid dimension values, leading to broken layouts. Using valid units ensures consistent rendering across browsers and compliance with CSS standards.
How to Fix
- Check the CSS value flagged in the error message.
- Verify the unit is a valid CSS unit (e.g.,
px,em,rem,%,vw,vh,vmin,vmax,ch,ex,cm,mm,in,pt,pc,s,ms,deg,rad,turn,fr). - Fix any typos, remove extra characters, or replace non-standard units with valid ones.
- If the value is meant to be unitless (like
line-height: 1.5), remove the erroneous unit entirely.
Examples
Incorrect: Misspelled unit
<div style="margin: 10pxl;">Hello</div>
The unit pxl is not a valid CSS unit. The validator reports an unknown dimension for 10pxl.
Correct: Valid unit
<div style="margin: 10px;">Hello</div>
Incorrect: Made-up unit
<style>
.box {
width: 50pixels;
height: 200hv;
}
</style>
Neither pixels nor hv are valid CSS units.
Correct: Standard CSS units
<style>
.box {
width: 50px;
height: 200vh;
}
</style>
Incorrect: Missing space causes concatenation
<style>
.container {
font-size: 1remx;
}
</style>
The extra x turns rem into the unknown dimension remx.
Correct: Proper unit
<style>
.container {
font-size: 1rem;
}
</style>
Incorrect: Unit where none is needed
<style>
p {
line-height: 1.5em2;
}
</style>
Correct: Unitless value or valid unit
<style>
p {
line-height: 1.5;
}
</style>
If you're confident the unit is valid and part of a newer CSS specification (such as container query units like cqi or cqb), the validator may not yet support it. In that case, the warning can be noted but may not indicate an actual problem in modern browsers. However, always double-check for typos first — the most common cause is simply a misspelled unit.
Private Use Area (PUA) characters are reserved ranges in Unicode whose interpretation is not specified by any encoding standard. Their meaning is determined entirely by private agreement between cooperating parties—such as a font vendor and its users. This means that a PUA character that renders as a custom icon in one font may appear as a blank square, a question mark, or a completely different glyph when that specific font is unavailable.
This warning commonly appears when using icon fonts like older versions of Font Awesome, Material Icons, or custom symbol fonts. These fonts map their icons to PUA code points. While this approach works visually when the font loads correctly, it creates several problems:
- Accessibility: Screen readers cannot interpret PUA characters meaningfully. A visually impaired user may hear nothing, hear "private use area character," or hear an unrelated description depending on their assistive technology.
- Portability: If the associated font fails to load (due to network issues, content security policies, or user preferences), the characters become meaningless boxes or blank spaces.
- Interoperability: Copy-pasting text containing PUA characters into another application, email client, or document will likely produce garbled or missing content since the receiving system won't know how to interpret those code points.
- Standards compliance: The W3C and Unicode Consortium both recommend against using PUA characters in publicly exchanged documents for exactly these reasons.
Sometimes PUA characters sneak into your HTML unintentionally—through copy-pasting from word processors, PDFs, or design tools that use custom encodings. Other times, they are inserted deliberately via CSS content properties or HTML entities by icon font libraries.
To fix this, identify where the PUA characters appear and replace them with standard alternatives. Use inline SVG for icons, standard Unicode symbols where appropriate (e.g., ✓ U+2713 instead of a PUA checkmark), or CSS background images. If you must use an icon font, hide the PUA character from assistive technology using aria-hidden="true" and provide an accessible label separately.
Examples
Problematic: PUA character used directly in HTML
<!-- The character below (U+E001) is a PUA code point -->
<p>Status: </p>
Without the specific icon font loaded, PUA characters like U+E001 render as missing glyphs or blank spaces.
Fixed: Using inline SVG with accessible label
<p>
Status:
<svg aria-hidden="true" width="16" height="16" viewBox="0 0 16 16">
<path d="M6 10.8L2.5 7.3 1.1 8.7 6 13.6 14.9 4.7 13.5 3.3z"/>
</svg>
<span>Complete</span>
</p>
Problematic: Icon font via CSS content property
<style>
.icon-check::before {
font-family: "MyIcons";
content: "\e001"; /* PUA character */
}
</style>
<span class="icon-check"></span>
Fixed: Icon font with accessibility safeguards
If you must continue using an icon font, hide the PUA character from assistive technology and provide an accessible alternative:
<style>
.icon-check::before {
font-family: "MyIcons";
content: "\e001";
}
</style>
<span class="icon-check" aria-hidden="true"></span>
<span class="sr-only">Checkmark</span>
Note that this approach still triggers the validator warning if the PUA character is detectable in the markup. The most robust fix is to avoid PUA characters entirely.
Fixed: Using a standard Unicode character
<p>Status: ✓ Complete</p>
The character ✓ (U+2713, CHECK MARK) is a standard Unicode character that is universally understood and renders consistently across platforms.
Problematic: PUA character from copy-paste
<p>Click here to download</p>
Invisible or unexpected PUA characters sometimes hide in text pasted from external sources. Inspect your source code carefully—many code editors can highlight non-ASCII characters or reveal their code points.
Fixed: Cleaned-up text
<p>Click here to download</p>
If you've audited your document and determined that the PUA characters are intentional and rendering correctly in your target environments, you may choose to accept this warning. However, for publicly accessible web pages, replacing PUA characters with standard alternatives is always the safer and more accessible choice.
When an HTML element contains the same attribute more than once, the browser must decide which value to use. According to the WHATWG HTML specification, the parser keeps only the first occurrence and silently discards the rest. This means any values you placed in the second (or subsequent) attribute are completely ignored — often leading to unexpected behavior that can be difficult to debug.
This issue commonly arises in a few scenarios:
- Copy-paste mistakes where code fragments are merged without deduplicating attributes.
- Template or CMS output where multiple systems each inject the same attribute onto an element.
- Attempting to assign multiple values by repeating the attribute instead of combining the values into one (especially common with
classandstyle).
Why this matters
- Unpredictable behavior: Since only the first value is kept, the duplicate is silently dropped. If you intended the second value, your page won't work as expected and there will be no visible error in the browser console.
- Accessibility concerns: Duplicate
idattributes or duplicate ARIA attributes can confuse assistive technologies, breaking navigation and screen reader announcements. - Standards compliance: Duplicate attributes violate the HTML specification and will cause validation errors, which can signal deeper quality issues in your markup.
- Maintainability: Code with duplicate attributes is harder to read and maintain, and it obscures the developer's intent.
Examples
❌ Duplicate class attribute
A common mistake is trying to add multiple classes by repeating the class attribute:
<div class="card" class="highlighted">Content</div>
The browser only applies "card" and ignores "highlighted" entirely.
✅ Merge classes into a single attribute
Combine all class names into one space-separated class attribute:
<div class="card highlighted">Content</div>
❌ Duplicate id attribute
<a id="home-link" id="nav-link">Home</a>
Only "home-link" is used; "nav-link" is discarded.
✅ Use a single id
Choose the appropriate id value. If you need multiple hooks for styling or scripting, use class for the additional identifier:
<a id="home-link" class="nav-link">Home</a>
❌ Duplicate style attribute
<p style="color: red;" style="font-weight: bold;">Important text</p>
Only color: red is applied; the bold style is lost.
✅ Combine styles into one attribute
<p style="color: red; font-weight: bold;">Important text</p>
❌ Duplicate data-* or event attributes
This also applies to data attributes and event handlers:
<button data-action="save" data-action="submit" onclick="handleClick()" onclick="trackEvent()">
Submit
</button>
✅ Use a single value per attribute
<button data-action="submit" onclick="handleClick(); trackEvent();">
Submit
</button>
❌ Duplicate attributes in template output
Templating systems sometimes produce duplicate attributes when multiple directives target the same element:
<input type="text" name="email" placeholder="Enter email" placeholder="you@example.com">
✅ Ensure templates produce a single attribute
Review your template logic so only one value is rendered:
<input type="text" name="email" placeholder="you@example.com">
How to fix it
- Search your markup for the attribute name flagged by the validator. Look for it appearing more than once on the same element.
- Decide which value is correct. If both values are needed, merge them into a single attribute (e.g., space-separated class names, semicolon-separated style declarations).
- Remove the duplicate. Delete the extra occurrence so only one remains.
- Check your build tools and templates. If the duplication comes from a CMS, templating engine, or JavaScript that sets attributes dynamically, fix the source rather than just the output.
- Re-validate your page to confirm the error is resolved.
The id attribute serves as a unique identifier for a single element in the DOM. The HTML specification explicitly requires that id values be unique across the entire document. When you reuse an id, you violate this contract, and the consequences can be subtle but far-reaching.
JavaScript behavior becomes unpredictable. Methods like document.getElementById() will only return the first element with a given id, silently ignoring any duplicates. This can cause scripts to target the wrong element or fail to interact with elements you expect them to reach.
CSS selectors may not apply as intended. While most browsers will style all elements with a duplicated id, this behavior is not guaranteed by the specification and can lead to inconsistencies across browsers.
Accessibility is compromised. Screen readers and other assistive technologies rely on unique IDs to associate labels with form controls (via for/id pairing), link aria-describedby or aria-labelledby references to specific elements, and navigate fragment identifiers (anchor links). Duplicate IDs break these associations, potentially making content confusing or unusable for people relying on assistive technology.
Fragment navigation breaks. When a URL contains a hash like #section-intro, the browser scrolls to the element with that id. If multiple elements share the same id, only the first one will be targeted, which may not be the intended destination.
Common causes of duplicate IDs include copy-pasting HTML blocks without updating the id values, dynamically generating content in a loop without appending a unique suffix, and reusing template partials that contain hardcoded id attributes.
To fix this issue, audit your document for repeated id values. If multiple elements need the same identifier for styling purposes, use the class attribute instead. If the id is needed for JavaScript or ARIA references, make each value unique — for example, by appending a number or descriptive suffix.
Examples
❌ Duplicate IDs on multiple elements
<div id="card">
<h2>First Card</h2>
</div>
<div id="card">
<h2>Second Card</h2>
</div>
Both <div> elements share id="card", which triggers the validation error.
✅ Use unique IDs
<div id="card-1">
<h2>First Card</h2>
</div>
<div id="card-2">
<h2>Second Card</h2>
</div>
✅ Use class instead when you don't need unique identification
<div class="card">
<h2>First Card</h2>
</div>
<div class="card">
<h2>Second Card</h2>
</div>
❌ Duplicate IDs break label associations
<label for="email">Work Email</label>
<input type="email" id="email" name="work_email">
<label for="email">Personal Email</label>
<input type="email" id="email" name="personal_email">
Both inputs share id="email", so the second <label> will incorrectly point to the first input. A screen reader user clicking "Personal Email" would be focused on the wrong field.
✅ Unique IDs for each label–input pair
<label for="work-email">Work Email</label>
<input type="email" id="work-email" name="work_email">
<label for="personal-email">Personal Email</label>
<input type="email" id="personal-email" name="personal_email">
❌ Duplicate IDs in dynamically repeated content
This often happens when generating HTML in a loop or reusing a template:
<section id="product">
<h2>Widget A</h2>
</section>
<section id="product">
<h2>Widget B</h2>
</section>
<section id="product">
<h2>Widget C</h2>
</section>
✅ Append a unique suffix
<section id="product-1">
<h2>Widget A</h2>
</section>
<section id="product-2">
<h2>Widget B</h2>
</section>
<section id="product-3">
<h2>Widget C</h2>
</section>
If no element actually needs to be uniquely identified, remove the id entirely and use a class or a data attribute instead.
The <a> element has an implicit ARIA role of link (when it has an href) or generic (when it doesn't). Certain ARIA state attributes, like aria-checked, are only valid on elements with specific roles that support them. For instance, aria-checked is designed for roles like checkbox, menuitemcheckbox, radio, switch, or option. If you place aria-checked on an <a> element without assigning one of these compatible roles, the validator raises this error because the attribute doesn't make sense in the context of the element's current role.
This matters for several reasons. Screen readers and other assistive technologies rely on the relationship between roles and their supported states to convey meaningful information to users. An aria-checked attribute on a plain link creates a confusing experience — the user hears that something is "checked" but the element is announced as a link, which isn't a concept that supports checked/unchecked states. This mismatch can make interfaces unusable for people relying on assistive technology.
To fix this issue, you need to either:
- Add an appropriate
rolethat supports the ARIA state attribute you're using. - Use a more semantically appropriate element, such as
<input type="checkbox">or<button>, which natively supports the concept of being checked or toggled. - Remove the unsupported ARIA attribute if it doesn't actually reflect the element's behavior.
Examples
Incorrect: aria-checked without a compatible role
This triggers the validation error because <a> doesn't support aria-checked without an explicit role:
<a href="#" aria-checked="true">Dark mode</a>
Fixed: Adding a compatible role
Adding role="menuitemcheckbox" (within a menu context) or role="switch" makes aria-checked valid:
<ul role="menu">
<li role="none">
<a href="#" role="menuitemcheckbox" aria-checked="true">Show notifications</a>
</li>
<li role="none">
<a href="#" role="menuitemcheckbox" aria-checked="false">Dark mode</a>
</li>
</ul>
Fixed: Using a <button> with role="switch" instead
In many cases, a <button> is a better semantic fit than an <a> for toggle-like interactions:
<button role="switch" aria-checked="true">Dark mode</button>
Correct: Tab list using <a> elements with proper roles
When building a tab interface with anchor elements, each tab needs role="tab" along with supporting attributes like aria-selected:
<div class="tab-interface">
<div role="tablist" aria-label="Settings">
<a role="tab" href="#panel-1" aria-selected="true" aria-controls="panel-1" id="tab-1">
General
</a>
<a role="tab" href="#panel-2" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">
Advanced
</a>
</div>
<div id="panel-1" role="tabpanel" tabindex="0" aria-labelledby="tab-1">
<p>General settings content</p>
</div>
<div id="panel-2" role="tabpanel" tabindex="0" aria-labelledby="tab-2" hidden>
<p>Advanced settings content</p>
</div>
</div>
Incorrect: aria-selected on a plain <a> without a role
<a href="/settings" aria-selected="true">Settings</a>
Fixed: Adding the appropriate role
<a href="/settings" role="tab" aria-selected="true">Settings</a>
When choosing a fix, always consider whether the <a> element is truly the best choice. If the element doesn't navigate the user to a new URL, a <button> is usually more appropriate. Reserve <a> for actual navigation, and use ARIA roles and states only when they accurately describe the element's behavior in the interface.
According to the HTML specification, the <a> element can exist without an href attribute, but in that case it represents a placeholder where a link might otherwise have been placed. However, the validator flags this as an issue because an <a> element without href and without role is ambiguous — browsers won't treat it as a link (it won't be focusable or keyboard-accessible), and assistive technologies won't know how to present it to users.
This matters for several reasons:
- Accessibility: Without
href, the<a>element loses its implicitrole="link"and is no longer announced as a link by screen readers. It also won't appear in the tab order, making it invisible to keyboard users. - Semantics: If the element is styled and scripted to behave like a button or link but lacks the proper attributes, it creates a disconnect between what users see and what the browser understands.
- Standards compliance: The spec expects you to be explicit about the element's purpose when
hrefis absent.
The most common cause of this issue is using <a> elements as JavaScript-only click targets without providing an href, or using them as styled containers without any interactive purpose.
How to Fix It
There are several approaches depending on your intent:
- Add an
hrefattribute if the element should be a link. This is the most common and recommended fix. - Add a
roleattribute if you're deliberately using<a>withouthreffor a specific purpose, such asrole="button". - Use a different element entirely. If it's not a link, consider using a
<button>,<span>, or another semantically appropriate element.
Examples
❌ Missing both href and role
<a>Click here</a>
This triggers the validator error because the <a> has neither href nor role.
❌ JavaScript-only handler without href
<a onclick="doSomething()">Submit</a>
Even with an event handler, the element lacks href and role, so it fails validation and is inaccessible to keyboard users.
✅ Fix by adding an href
<a href="/about">About us</a>
Adding href makes it a proper hyperlink — focusable, keyboard-accessible, and recognized by screen readers.
✅ Fix by adding role for a non-link purpose
<a role="button" tabindex="0" onclick="doSomething()">Submit</a>
If you must use <a> without href as a button, add role="button" and tabindex="0" to ensure it's focusable and properly announced. However, consider using a real <button> instead.
✅ Better: use the right element
<button type="button" onclick="doSomething()">Submit</button>
If the element triggers an action rather than navigating somewhere, a <button> is the correct semantic choice. It's focusable by default, responds to keyboard events, and doesn't need extra attributes.
✅ Placeholder anchor (intentional non-link)
<a role="link" aria-disabled="true">Coming soon</a>
If you're intentionally showing a placeholder where a link will eventually appear, you can add a role and indicate its disabled state for assistive technologies. Alternatively, use a <span> with appropriate styling to avoid the issue altogether.
The HTML specification defines <button> as a versatile interactive element, but its behavior changes depending on context. When a <button> is placed inside a <form> without a type attribute, it defaults to type="submit", which can cause unexpected form submissions. The validator flags this because relying on the implicit default is ambiguous and error-prone. Explicitly setting the type attribute makes the button's intent clear to both developers and browsers.
The three valid values for the type attribute are:
submit— submits the parent form's data to the server.reset— resets all form controls to their initial values.button— performs no default action; behavior is defined via JavaScript.
When a <button> is given an ARIA role of checkbox, switch, or menuitemcheckbox, the validator expects an aria-checked attribute to accompany it. These roles describe toggle controls that have a checked or unchecked state, so assistive technologies need to know the current state. Without aria-checked, screen readers cannot communicate whether the control is on or off, making the interface inaccessible.
The aria-checked attribute accepts the following values:
true— the control is checked or on.false— the control is unchecked or off.mixed— the control is in an indeterminate state (valid forcheckboxandmenuitemcheckboxroles only).
How to fix it
For standard buttons, add the type attribute with the appropriate value. If the button triggers JavaScript behavior and is not meant to submit a form, use type="button". If it submits a form, use type="submit" explicitly to make the intent clear.
For toggle buttons, ensure the <button> has both a role attribute (such as checkbox or switch) and an aria-checked attribute that reflects the current state. You should also include type="button" to prevent unintended form submission. Use JavaScript to toggle the aria-checked value when the user interacts with the button.
Examples
Missing type attribute
This triggers the validator warning because the type is not specified:
<form action="/search">
<input type="text" name="q">
<button>Search</button>
</form>
Fixed by adding an explicit type:
<form action="/search">
<input type="text" name="q">
<button type="submit">Search</button>
</form>
Button used outside a form without type
<button onclick="openMenu()">Menu</button>
Fixed by specifying type="button":
<button type="button" onclick="openMenu()">Menu</button>
Toggle button missing aria-checked
A button with role="switch" but no aria-checked attribute:
<button type="button" role="switch">Dark Mode</button>
Fixed by adding aria-checked:
<button type="button" role="switch" aria-checked="false">Dark Mode</button>
Checkbox-style toggle button
A button acting as a checkbox must include both role="checkbox" and aria-checked:
<button type="button" role="checkbox" aria-checked="false">
Enable notifications
</button>
Complete toggle example with all required attributes
<button type="button" role="switch" aria-checked="false" id="wifi-toggle">
Wi-Fi
</button>
<script>
document.getElementById("wifi-toggle").addEventListener("click", function () {
const isChecked = this.getAttribute("aria-checked") === "true";
this.setAttribute("aria-checked", String(!isChecked));
});
</script>
In this example, the type="button" prevents form submission, the role="switch" tells assistive technologies this is a toggle, and aria-checked is updated dynamically to reflect the current state. This ensures the button is fully accessible and passes validation.
The <dl> element represents a description list — a collection of terms (<dt>) paired with their descriptions (<dd>). According to the HTML specification, the permitted content of a <dl> is either groups of <dt> and <dd> elements directly, or <div> elements that wrap those groups. This <div> wrapping option exists specifically to help with styling, since it lets you apply CSS to a term-description pair as a unit.
However, these wrapper <div> elements are not general-purpose containers inside <dl>. The spec requires that each <div> inside a <dl> contains at least one <dt> or <dd> child. A <div> that is empty, or that contains other elements like <span>, <p>, or another <div>, violates this rule and produces a validation error.
This matters for several reasons. Screen readers and assistive technologies rely on the semantic structure of description lists to convey the relationship between terms and definitions. An empty or improperly structured <div> inside a <dl> breaks that semantic contract, potentially confusing both assistive technology and browsers. Keeping your markup valid also ensures consistent rendering across all browsers.
How to Fix It
- Ensure every
<div>inside a<dl>contains at least one<dt>or<dd>— don't leave wrapper<div>elements empty. - Don't put non-
<dt>/<dd>content directly inside these<div>wrappers — elements like<span>,<p>, or nested<div>elements should be placed inside a<dt>or<dd>, not as siblings to them. - Remove unnecessary
<div>wrappers — if a<div>inside a<dl>serves no styling or grouping purpose, remove it entirely.
Examples
❌ Empty <div> inside a <dl>
<dl>
<div>
</div>
<div>
<dt>HTML</dt>
<dd>A markup language for structuring web content.</dd>
</div>
</dl>
The first <div> is empty and has no <dt> or <dd> child, triggering the error.
❌ <div> with only non-<dt>/<dd> children
<dl>
<div>
<p>This is a description list:</p>
</div>
<div>
<dt>CSS</dt>
<dd>A style sheet language for describing presentation.</dd>
</div>
</dl>
The first <div> contains a <p> element but no <dt> or <dd>, which is invalid.
✅ Each <div> contains <dt> and <dd> elements
<dl>
<div>
<dt>HTML</dt>
<dd>A markup language for structuring web content.</dd>
</div>
<div>
<dt>CSS</dt>
<dd>A style sheet language for describing presentation.</dd>
</div>
</dl>
✅ Using <dl> without <div> wrappers
If you don't need <div> elements for styling, you can place <dt> and <dd> directly inside the <dl>:
<dl>
<dt>HTML</dt>
<dd>A markup language for structuring web content.</dd>
<dt>CSS</dt>
<dd>A style sheet language for describing presentation.</dd>
</dl>
✅ A <dt> with multiple <dd> descriptions in a <div>
A single term can have multiple descriptions. The <div> is valid as long as it contains at least one <dt> or <dd>:
<dl>
<div>
<dt>JavaScript</dt>
<dd>A programming language for the web.</dd>
<dd>Supports event-driven and functional programming.</dd>
</div>
</dl>
The aria-expanded attribute cannot be used on a plain div element without also specifying a role attribute.
The aria-expanded attribute indicates whether a grouping of content that the element owns or controls is currently expanded or collapsed. However, this attribute is only valid on elements that have an appropriate implicit or explicit role. A plain div has no implicit ARIA role, so you must assign one explicitly.
The aria-expanded attribute is commonly used with interactive roles such as button, combobox, treeitem, or link. Adding the correct role tells assistive technologies what kind of element the user is interacting with, making aria-expanded meaningful in context.
HTML Examples
❌ Invalid: aria-expanded on a plain div
<div aria-expanded="false">
Menu content
</div>
✅ Valid: aria-expanded with an appropriate role
<div role="button" aria-expanded="false">
Menu content
</div>
Alternatively, consider using a native HTML element that already carries the correct semantics, which avoids the need for a role attribute entirely:
<button aria-expanded="false">
Toggle Menu
</button>
Using a native <button> is generally preferred over <div role="button"> because it comes with built-in keyboard interaction and focus behavior.
The aria-required attribute tells assistive technologies that a form field must be filled in before the form can be submitted. However, this attribute is only valid on elements that function as interactive widgets. A bare div has no implicit ARIA role, so assistive technologies have no context for what kind of input is expected. The validator flags this because an aria-required attribute on a generic div is effectively meaningless without additional ARIA attributes that define the element's role and behavior.
This matters for several reasons:
- Accessibility: Screen readers and other assistive technologies rely on roles to understand how to present an element to users. Without a role,
aria-requiredprovides incomplete information. - Standards compliance: The WAI-ARIA specification defines which attributes are allowed on which roles. Using
aria-requiredwithout an established role violates these constraints. - Browser behavior: Browsers may ignore or misinterpret ARIA attributes when they appear on elements that lack the proper role context.
How to fix it
Option 1: Use native semantic HTML (preferred)
Whenever possible, use native HTML form elements. They come with built-in accessibility semantics, keyboard interaction, and validation — no ARIA needed.
Replace a div with aria-required="true" with an appropriate form control using the native required attribute:
<input type="text" required>
<select required>
<option value="">Choose one</option>
<option value="1">Option 1</option>
</select>
<textarea required></textarea>
Option 2: Add an appropriate role attribute
When you must use a div as a custom widget (styled and enhanced with CSS and JavaScript), add the correct role attribute to give it semantic meaning. Choose the role that matches the widget's actual behavior — don't just pick one arbitrarily.
Common roles that support aria-required:
combobox— a custom dropdown with text inputlistbox— a custom selection listradiogroup— a group of radio-like optionsspinbutton— a numeric stepper (also requiresaria-valuemax,aria-valuemin, andaria-valuenow)textbox— a custom text input
Option 3: Add other qualifying ARIA attributes
For certain widgets like sliders or spinbuttons, you may need aria-valuemax, aria-valuemin, and aria-valuenow in addition to (or as part of) defining the role. These attributes inherently establish a widget context.
Examples
❌ Invalid: aria-required on a plain div
<div aria-required="true">
<div data-value="One">1</div>
<div data-value="Two">2</div>
<div data-value="Three">3</div>
</div>
This triggers the validation error because the div has no role or other ARIA attributes to define what kind of widget it is.
✅ Fixed: Adding the appropriate role
<div aria-required="true" role="radiogroup" aria-label="Pick a number">
<div role="radio" aria-checked="false" tabindex="0">1</div>
<div role="radio" aria-checked="false" tabindex="0">2</div>
<div role="radio" aria-checked="false" tabindex="0">3</div>
</div>
Adding role="radiogroup" gives the div a semantic identity. Note that child elements also need appropriate roles and attributes for the widget to be fully accessible.
✅ Fixed: Using native HTML instead
<fieldset>
<legend>Pick a number</legend>
<label><input type="radio" name="number" value="1" required> 1</label>
<label><input type="radio" name="number" value="2"> 2</label>
<label><input type="radio" name="number" value="3"> 3</label>
</fieldset>
This approach uses native radio buttons with the required attribute, eliminating the need for ARIA entirely. The browser handles accessibility, keyboard navigation, and form validation automatically.
✅ Fixed: A custom spinbutton with value attributes
<div role="spinbutton"
aria-required="true"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="50"
aria-label="Quantity"
tabindex="0">
50
</div>
For a spinbutton role, you must also provide aria-valuemin, aria-valuemax, and aria-valuenow to fully describe the widget's state.
The HTML specification defines a strict content model for the <ul> (unordered list) element: its permitted content is zero or more <li> elements, optionally intermixed with <script> and <template> elements. A <div> is not among these allowed children, so placing one directly inside a <ul> produces a validation error.
This issue commonly arises when developers try to group or wrap list items for styling or layout purposes. For example, you might want to add a container around certain <li> elements for flexbox or grid alignment, or you might be using a templating system that injects wrapper <div> elements into your list markup.
Why this matters
- Browser parsing inconsistencies: When browsers encounter invalid nesting, they attempt to fix the DOM structure automatically, but different browsers may handle it differently. This can lead to unexpected rendering where list items appear outside their intended container or styles break unpredictably.
- Accessibility: Screen readers and assistive technologies rely on correct semantic structure to convey list relationships to users. A
<div>breaking the<ul>→<li>relationship can cause assistive tools to misinterpret or skip list content entirely. - Standards compliance: Invalid HTML can cause cascading parser errors — note that the validator message says "Suppressing further errors from this subtree," meaning additional issues within that structure may be hidden from you.
How to fix it
- Move the
<div>inside the<li>: If you need a wrapper for styling, place it inside the list item rather than around it. - Remove the
<div>entirely: If it serves no purpose, simply remove it and let the<li>elements sit directly inside the<ul>. - Use CSS on the
<li>elements: In many cases, you can apply the styles you need directly to the<li>elements without an extra wrapper. - Use
role="list"on a<div>parent: If your layout truly requires<div>wrappers, consider restructuring with ARIA roles, though native semantic elements are always preferred.
Examples
❌ Incorrect: <div> as a direct child of <ul>
<ul>
<div>
<li>Apples</li>
<li>Bananas</li>
</div>
<div>
<li>Carrots</li>
<li>Dates</li>
</div>
</ul>
✅ Correct: Move the <div> inside each <li>
<ul>
<li><div>Apples</div></li>
<li><div>Bananas</div></li>
<li><div>Carrots</div></li>
<li><div>Dates</div></li>
</ul>
✅ Correct: Remove the <div> entirely
<ul>
<li>Apples</li>
<li>Bananas</li>
<li>Carrots</li>
<li>Dates</li>
</ul>
❌ Incorrect: Using a <div> as a styling wrapper around list items
<ul class="product-list">
<div class="row">
<li>Product A</li>
<li>Product B</li>
<li>Product C</li>
</div>
</ul>
✅ Correct: Apply layout styles directly to the <ul> and <li> elements
<ul class="product-list row">
<li>Product A</li>
<li>Product B</li>
<li>Product C</li>
</ul>
❌ Incorrect: Template or component wrapper inserting a <div>
This often happens in frameworks where a component renders a wrapping <div>:
<ul>
<div class="list-item-wrapper">
<li>Item 1</li>
</div>
<div class="list-item-wrapper">
<li>Item 2</li>
</div>
</ul>
✅ Correct: Move the wrapper class to the <li> itself
<ul>
<li class="list-item-wrapper">Item 1</li>
<li class="list-item-wrapper">Item 2</li>
</ul>
The same rule applies to <ol> (ordered list) elements — they share the same content model restriction. Always ensure that <li> is the direct child of <ul> or <ol>, and place any additional wrapper elements inside the <li> rather than around it.
According to the HTML specification, the <dl> element's content model requires one or more groups, where each group consists of one or more <dt> elements followed by one or more <dd> elements. Alternatively, these groups can be wrapped in <div> elements for styling purposes. An empty <dl> or one missing either side of the pairing is invalid.
This matters for several reasons. Screen readers and other assistive technologies rely on the proper structure of description lists to convey the relationship between terms and their descriptions. When the structure is incomplete, these tools cannot communicate the intended meaning to users. Browsers may also render malformed description lists inconsistently, leading to unpredictable layouts.
To fix this issue, make sure every <dl> contains at least one <dt> element paired with at least one <dd> element. If you only have a <dd>, add the corresponding <dt>. If you only have a <dt>, add the corresponding <dd>. If the list is empty or you don't have content for both parts, consider whether a <dl> is the right element for your use case—a <ul> or <p> might be more appropriate.
Examples
Missing <dt> element
A <dd> without its corresponding <dt> triggers this error:
<dl>
<dd>A box without hinges, key, or lid, yet golden treasure inside is hid.</dd>
</dl>
Add the missing <dt> to complete the group:
<dl>
<dt>Egg</dt>
<dd>A box without hinges, key, or lid, yet golden treasure inside is hid.</dd>
</dl>
Missing <dd> element
A <dt> without a following <dd> also triggers this error:
<dl>
<dt>Egg</dt>
</dl>
Add the missing <dd> to provide the description:
<dl>
<dt>Egg</dt>
<dd>A box without hinges, key, or lid, yet golden treasure inside is hid.</dd>
</dl>
Empty <dl> element
An empty description list is invalid:
<dl></dl>
Either populate it with a complete term-description group or remove the element entirely.
Multiple terms and descriptions
A single <dt> can have multiple <dd> elements, and multiple <dt> elements can share the same <dd>. Both are valid:
<dl>
<dt>Egg</dt>
<dt>Ova</dt>
<dd>A box without hinges, key, or lid, yet golden treasure inside is hid.</dd>
<dd>An oval body laid by birds, reptiles, and other creatures.</dd>
</dl>
Using <div> wrappers
You can wrap each name-value group in a <div> for styling purposes, but each <div> must still contain the required <dt> and <dd> pairing:
<dl>
<div>
<dt>Egg</dt>
<dd>A box without hinges, key, or lid, yet golden treasure inside is hid.</dd>
</div>
<div>
<dt>Sun</dt>
<dd>An eye in a blue face saw an eye in a green face.</dd>
</div>
</dl>
The <dl> element represents a description list — a collection of name-value groups where <dt> elements provide the terms (or names) and <dd> elements provide the associated descriptions (or values). According to the HTML specification, the content model for <dl> requires that each <dt> group be followed by one or more <dd> elements. A <dl> with only <dt> elements and no <dd> elements is invalid HTML.
This matters for several reasons. Assistive technologies like screen readers rely on the proper <dt>/<dd> pairing to convey the relationship between terms and their descriptions. A description list without descriptions is semantically meaningless — it's like having a dictionary with words but no definitions. Browsers may also render the list inconsistently when the expected structure is incomplete.
Common causes of this error include:
- Accidentally using
<dl>and<dt>to create a simple list instead of using<ul>or<ol>. - Dynamically generated content where the
<dd>elements are missing due to empty data. - Incomplete markup where the developer forgot to add the description elements.
To fix this issue, make sure every <dt> element inside a <dl> is followed by at least one <dd> element. If you don't actually need a description list, consider using a different element like <ul> for simple lists.
Examples
Invalid: <dl> with only <dt> and no <dd>
<dl>
<dt>The Meaning of Life</dt>
</dl>
This is invalid because the <dt> term has no corresponding <dd> description.
Fixed: Adding a <dd> element
<dl>
<dt>The Meaning of Life</dt>
<dd>A philosophical question about the significance of existence.</dd>
</dl>
Invalid: Multiple terms without any descriptions
<dl>
<dt>HTML</dt>
<dt>CSS</dt>
<dt>JavaScript</dt>
</dl>
This triggers the error because none of the terms have associated descriptions.
Fixed: Each term with a description
<dl>
<dt>HTML</dt>
<dd>A markup language for structuring web content.</dd>
<dt>CSS</dt>
<dd>A style sheet language for describing presentation.</dd>
<dt>JavaScript</dt>
<dd>A programming language for web interactivity.</dd>
</dl>
Valid: Multiple terms sharing a single description
Multiple <dt> elements can share a single <dd>, which is useful for synonyms or aliases:
<dl>
<dt>Laptop</dt>
<dt>Notebook</dt>
<dd>A portable personal computer with a clamshell form factor.</dd>
</dl>
Valid: A single term with multiple descriptions
A <dt> can also be followed by multiple <dd> elements:
<dl>
<dt>Python</dt>
<dd>A large constricting snake.</dd>
<dd>A high-level programming language.</dd>
</dl>
Valid: Using <div> to wrap name-value groups
The HTML spec allows wrapping each <dt>/<dd> group in a <div> for styling purposes. Each <div> must still contain at least one <dd>:
<dl>
<div>
<dt>Name</dt>
<dd>Jane Doe</dd>
</div>
<div>
<dt>Email</dt>
<dd>jane@example.com</dd>
</div>
</dl>
Alternative: Use <ul> when descriptions aren't needed
If you only need a list of items without descriptions, a <dl> is the wrong element. Use an unordered list instead:
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
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