HTML Guides for bad value
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 srcset attribute lets browsers intelligently choose which image to load based on the viewport size and device pixel ratio. Each entry in a srcset consists of a URL followed by either a width descriptor (like 300w) or a pixel density descriptor (like 2x). When using width descriptors, the value represents the intrinsic pixel width of the image file — that is, the actual width of the image as stored on disk.
A width descriptor of 0w violates the HTML specification, which requires width descriptors to be integers greater than zero. A zero-width image cannot meaningfully participate in the browser's source selection process. The browser uses these width values in combination with the sizes attribute to calculate which image best fits the current layout — a value of zero would break this calculation entirely.
This issue commonly occurs when:
- Image dimensions are dynamically generated and a fallback of
0is used for missing data. - A placeholder or empty state is accidentally included in the
srcset. - A CMS or build tool outputs a
0wdescriptor for images whose dimensions weren't computed.
Why it matters
- Standards compliance: The HTML specification explicitly requires width descriptors to be positive integers. Validators will flag
0was an error. - Browser behavior: While browsers may silently ignore the invalid entry, you can't rely on consistent handling across all browsers and versions. The image selection algorithm may behave unpredictably.
- Performance: A well-formed
srcsetis key to responsive image loading. Invalid descriptors can prevent browsers from selecting the optimal image, leading to unnecessarily large downloads or poor image quality.
How to fix it
- Open the image file associated with the
0wdescriptor and check its actual pixel width using an image editor or the command line. - Replace
0wwith the correct width (e.g.,150wfor a 150-pixel-wide image). - If the image is truly zero-width or a placeholder, remove that entry from the
srcsetentirely. - Ensure every remaining entry has a unique, positive width descriptor.
Examples
❌ Invalid: width descriptor of 0w
<picture>
<source
srcset="/images/icon_placeholder.png 0w,
/images/icon_large.png 600w"
media="(max-width: 600px)">
<img src="/images/icon_fallback.png" alt="App logo">
</picture>
The 0w descriptor triggers the validation error because zero is not a valid width.
✅ Fixed: all width descriptors are positive
<picture>
<source
srcset="/images/icon_small.png 300w,
/images/icon_large.png 600w"
media="(max-width: 600px)">
<img src="/images/icon_fallback.png" alt="App logo">
</picture>
Each entry now has a meaningful width descriptor (300w and 600w) that reflects the actual pixel width of the corresponding image.
❌ Invalid: 0w on an <img> element
<img
srcset="/images/hero_tiny.jpg 0w,
/images/hero_medium.jpg 800w,
/images/hero_large.jpg 1200w"
sizes="100vw"
src="/images/hero_medium.jpg"
alt="Mountain landscape">
✅ Fixed: placeholder entry removed or corrected
If the tiny image is 400 pixels wide, use 400w:
<img
srcset="/images/hero_tiny.jpg 400w,
/images/hero_medium.jpg 800w,
/images/hero_large.jpg 1200w"
sizes="100vw"
src="/images/hero_medium.jpg"
alt="Mountain landscape">
Alternatively, if the image doesn't belong in the set at all, simply remove it:
<img
srcset="/images/hero_medium.jpg 800w,
/images/hero_large.jpg 1200w"
sizes="100vw"
src="/images/hero_medium.jpg"
alt="Mountain landscape">
When using a build tool or CMS that generates srcset values dynamically, add a check to filter out any entries where the computed width is zero or missing before rendering the attribute. This prevents the invalid markup from reaching production.
A tabindex value that starts with $ is a template variable, such as $velocityCount or ${index}, that reached the page without being replaced by a number.
tabindex takes a valid integer: an optional - followed by digits, like 0, -1 or 2. The validator reads the value from the first character, and a $ there fails the check straight away.
The $ usually comes from a template. Apache Velocity prints any reference it can't resolve exactly as written, so a misspelled variable ends up in the HTML as plain text. So does $velocityCount, the old loop counter that Velocity 2.0 dropped in favor of $foreach.count and $foreach.index. Velocity doesn't do arithmetic inside a plain reference either, which means $velocityCount-1 never becomes a number; do the subtraction in a #set directive. In JavaScript, ${index} only gets filled in inside a template literal (backticks), so markup built from a single- or double-quoted string keeps it as text.
Browsers ignore a tabindex they can't parse and treat the element as if the attribute were missing. A <div> meant to take keyboard focus stays out of the tab order, so keyboard users can't reach it.
Fix the template so it outputs a number, or drop the variable. Tab panels rarely need a counter anyway. The ARIA tabs pattern puts tabindex="0" on a panel with no focusable content, and a counter would give later panels positive values like 1 and 2, which move them ahead of the rest of the page in the tab order.
Invalid example
<div role="tabpanel" id="panel-books" tabindex="$velocityCount-1">
<p>Browse the book catalog.</p>
</div>
Valid example
<div role="tabpanel" id="panel-books" tabindex="0">
<p>Browse the book catalog.</p>
</div>
The type attribute on an <a> element is an advisory hint that tells the browser what media type (MIME type) to expect at the linked resource. A valid MIME type follows a strict format: a type, a / separator, and a subtype (e.g., text/html, application/pdf, image/png). Each part must consist of token characters — letters, digits, and certain symbols — but not spaces.
This validation error occurs when the MIME type value contains a space or other unexpected character in a position where only token characters or a / are allowed. Common causes include:
- Accidental spaces within the MIME type (e.g.,
application/ pdforapplication /pdf). - Multiple MIME types separated by spaces (e.g.,
text/html text/plain), which is not valid since the attribute accepts only a single MIME type. - Typos or copy-paste errors that introduce whitespace or non-token characters.
While the type attribute is purely advisory and browsers won't refuse to follow a link based on it, an invalid value defeats its purpose and signals sloppy markup. Standards-compliant HTML ensures your pages are interpreted consistently and avoids confusing tools, screen readers, or other user agents that may parse this attribute.
Examples
Incorrect: Space within the MIME type
<a href="report.pdf" type="application/ pdf">Download Report</a>
The space after the / makes this an invalid MIME type.
Incorrect: Multiple MIME types separated by a space
<a href="data.csv" type="text/csv text/plain">Download Data</a>
The type attribute only accepts a single MIME type. The space between text/csv and text/plain triggers the error.
Incorrect: Leading or trailing spaces
<a href="photo.jpg" type=" image/jpeg ">View Photo</a>
Spaces before or after the MIME type are not permitted.
Correct: Valid MIME type with no spaces
<a href="report.pdf" type="application/pdf">Download Report</a>
Correct: Other common valid MIME types
<a href="data.csv" type="text/csv">Download Data</a>
<a href="photo.jpg" type="image/jpeg">View Photo</a>
<a href="archive.zip" type="application/zip">Download Archive</a>
Correct: MIME type with a parameter
MIME types can include parameters separated by a semicolon — no spaces are required, though a single space after the semicolon is permitted per the MIME specification:
<a href="page.html" type="text/html; charset=utf-8">View Page</a>
How to Fix
- Inspect the
typevalue — look for any spaces within the type or subtype portions (before or after the/). - Remove extra spaces — ensure the value is a single, properly formatted MIME type like
type/subtype. - Use only one MIME type — if you've listed multiple types, pick the one that accurately describes the linked resource.
- Verify the MIME type is valid — consult the IANA Media Types registry to confirm you're using a recognized type.
- Consider removing the attribute — since
typeis purely advisory on<a>elements, if you're unsure of the correct MIME type, omitting the attribute entirely is perfectly valid.
A MIME type (also called a media type) always follows the format type/subtype, such as text/html, application/pdf, or image/jpeg. The "type" part indicates the general category (e.g., text, image, application, audio, video), and the "subtype" specifies the exact format within that category. When the validator reports "Subtype missing," it means the value you provided either lacks the /subtype portion or isn't a valid MIME type structure at all.
A common cause of this error is misunderstanding the purpose of the type attribute on <a> elements. The type attribute is not used to change the behavior or appearance of the link (the way type works on <input> or <button> elements). Instead, it serves as an advisory hint to the browser about what kind of resource the link points to. The browser may use this information to adjust its UI — for example, showing a download prompt for application/pdf — but it is not required to act on it.
Because of this misunderstanding, developers sometimes write type="button" on an <a> element, thinking it will make the link behave like a button. The value button is not a valid MIME type (it has no subtype), so the validator flags it. If you need a button, use a <button> element instead. If you need a styled link that looks like a button, keep the <a> element and use CSS for styling.
Why this matters
- Standards compliance: The HTML specification requires the
typeattribute on<a>to be a valid MIME type string. An invalid value violates the spec and may be ignored by browsers or cause unexpected behavior. - Accessibility and semantics: Using
type="button"on a link can create confusion about the element's role. Screen readers and assistive technologies rely on correct semantics to convey meaning to users. - Browser behavior: While browsers are generally forgiving, an invalid
typevalue provides no useful information and could interfere with how the browser handles the linked resource.
How to fix it
- If you intended to hint at the linked resource's MIME type, make sure you provide a complete
type/subtypevalue — for example,application/pdfrather than justapplication. - If you used
typeto try to style or change the link's behavior, remove thetypeattribute entirely. Use CSS for visual styling or switch to a more appropriate element like<button>. - If you don't need the
typeattribute, simply remove it. It's entirely optional on<a>elements.
Examples
Incorrect: missing subtype
<a href="report.pdf" type="application">Download report</a>
The value application is incomplete — it's missing the subtype portion after the slash.
Incorrect: not a MIME type at all
<a href="/order.php" type="button">Submit</a>
The value button is not a MIME type. This often stems from confusing the type attribute on <a> with the type attribute on <input> or <button>.
Correct: valid MIME type
<a href="report.pdf" type="application/pdf">Download report</a>
<a href="photo.jpeg" type="image/jpeg">See a photo</a>
The type attribute uses a properly formatted MIME type with both a type and subtype.
Correct: removing the attribute entirely
<a href="/order.php">Submit</a>
If the type attribute isn't serving a real purpose, the simplest fix is to remove it.
Correct: using a button element instead
<button type="submit">Submit</button>
If you need actual button behavior (such as submitting a form), use a <button> element rather than an <a> element with an invalid type.
The type attribute on a <button> only accepts three keywords — submit, reset, and button — so any other value is rejected.
type is an enumerated attribute, not a free-form one. submit posts the form (and is what a button does when the attribute is absent), reset clears the form fields, and button does nothing on its own and is meant to be wired up with JavaScript. Anything outside that set is invalid markup, and the browser falls back to submit, so a button you expected to stay inert may submit the form instead.
If you want the default behavior, leave the attribute off or write type="submit" explicitly; if the button should not submit, use type="button".
Invalid example
<button type="default">Save</button>
Valid example
<button type="submit">Save</button>
The type attribute on <input> only accepts the keywords defined in the HTML standard, so any other value, such as phone, social or the name of a website, is reported as an error.
type is an enumerated attribute. The valid keywords are text, search, email, url, tel, password, number, range, date, month, week, time, datetime-local, color, checkbox, radio, file, hidden, submit, reset, button and image. A browser that meets an unknown value treats the field as type="text", so the form still seems to work, but you lose the mobile keyboard, the built-in validation and the autofill hints that the right type gives you.
Pick the keyword that describes the data the field collects, not the topic of the field. A link to a profile page is a url, a phone number is tel, and an address you can send mail to is email. When no type fits, such as a username or a postal code, use type="text" and describe the value with autocomplete, inputmode or pattern. If you need a hook for scripts or styles, put it in name, id, class or a data-* attribute instead of type.
Invalid example
<form>
<label for="profile">Social profile</label>
<input type="social" id="profile" name="profile">
<label for="phone">Phone</label>
<input type="phone" id="phone" name="phone">
</form>
Valid example
<form>
<label for="profile">Social profile</label>
<input type="url" id="profile" name="profile" placeholder="https://example.com/yourname">
<label for="phone">Phone</label>
<input type="tel" id="phone" name="phone" autocomplete="tel">
</form>
The type attribute on a <link> element specifies the MIME type of the linked resource. MIME types follow a specific format: a type and subtype separated by a single forward slash, like text/css, image/png, or application/json. They never contain the :// sequence found in URLs.
This error most commonly occurs when a URL is accidentally placed in the type attribute instead of in the href attribute, or when the attributes are confused with one another. For example, writing type="https://example.com/style.css" triggers this error because the validator encounters the colon in https: where it expects a valid MIME type token.
Another common cause is copying type values from other contexts (such as XML namespaces or schema references) that use URL-like strings, and mistakenly applying them to the type attribute.
Why this matters
- Standards compliance: The HTML specification requires the
typeattribute to contain a valid MIME type. Invalid values violate the spec and may cause browsers to misinterpret or ignore the linked resource. - Browser behavior: Browsers use the
typeattribute as a hint for how to handle the resource. An invalid MIME type could lead the browser to skip loading the resource entirely, causing missing styles, icons, or other assets. - Maintainability: Incorrect attribute values signal to other developers (and automated tools) that something is misconfigured, making the code harder to maintain.
How to fix it
- Check that
typecontains a valid MIME type, not a URL or other string. Common valid values includetext/css,image/png,image/x-icon,image/svg+xml, andapplication/rss+xml. - Ensure URLs are in the
hrefattribute, nottype. - Consider removing
typeentirely. For stylesheets, modern browsers default totext/css, sotype="text/css"is optional. For many use cases, thetypeattribute can be safely omitted.
Examples
❌ Incorrect: URL used as the type value
<link rel="stylesheet" type="https://example.com/style.css">
The validator sees the colon in https: and reports the error because this is a URL, not a MIME type.
❌ Incorrect: Attributes swapped
<link rel="icon" type="https://example.com/favicon.png" href="image/png">
Here the type and href values have been accidentally swapped.
✅ Correct: Valid MIME type with proper href
<link rel="icon" type="image/png" href="https://example.com/favicon.png">
✅ Correct: Stylesheet with valid type
<link rel="stylesheet" type="text/css" href="/css/style.css">
✅ Correct: Stylesheet without type (also valid)
<link rel="stylesheet" href="/css/style.css">
Since browsers default to text/css for stylesheets, omitting type is perfectly valid and keeps your markup cleaner.
✅ Correct: RSS feed link
<link rel="alternate" type="application/rss+xml" title="RSS Feed" href="/feed.xml">
The type attribute of a <script> element has extra text after its JavaScript MIME type, such as a ; charset=utf-8 parameter or a piece of another attribute.
When a <script> has a type, the HTML standard tells browsers to run it as JavaScript only if the value is exactly a JavaScript MIME type like text/javascript. Letter case and surrounding spaces don't matter, but parameters aren't allowed. Any other value turns the element into a data block, which the browser never runs. So a <script> with src often gets a second error too: data blocks can't have a src attribute.
There are two common causes. Older code sometimes copied ; charset=utf-8 from an HTTP Content-Type header, where parameters are allowed, into the type attribute, where they aren't. Or someone typed text/javascript" async="async into a CMS field or plugin setting that fills in type, hoping to add a second attribute. The template escaped the quotes as ", so async stayed inside the type value.
For JavaScript, remove type. The default is already text/javascript, and the validator reports an explicit one as unnecessary. Write other options like async or defer as separate attributes. If the script file needs a declared encoding, set it in the Content-Type header the server sends for that file.
Invalid example
<script src="/js/app.js" type="text/javascript; charset=utf-8"></script>
<script src="/js/stats.js" type="text/javascript" async="async"></script>
Valid example
<script src="/js/app.js"></script>
<script src="/js/stats.js" async></script>
The width of an <img> holds the text NaN, which usually means a script or template calculated the size from a missing or non-numeric value.
The width attribute takes a non-negative integer: digits only. NaN ("not a number") is what JavaScript returns when arithmetic runs on undefined or a non-numeric string, for example Math.round(data.width * scale) when data.width is missing. Writing that result into the markup puts the literal text NaN in the attribute. Other words that start with that letter, such as null or none, trigger the same message with a lowercase n.
Browsers can't read a number from NaN, so they ignore the attribute. The image then gets no reserved space before it loads, and the content below it shifts once it arrives. The height attribute often has the same bug and gets its own error.
Fix the code that produces the value. Check that the number is finite before you write it (Number.isFinite(width) in JavaScript), and leave the attribute out when the size isn't known.
Invalid example
<img src="photo.jpg" alt="A red car" width="NaN" height="NaN">
Valid example
<img src="photo.jpg" alt="A red car" width="640" height="480">
A stray double quote ended up inside the width value of an <img>, usually because the opening quote is missing (width=200") or the quotes don't match (width='200"').
The width attribute takes a non-negative integer: digits only, with no quotes, units or spaces. Without an opening quote, the browser reads the value as unquoted, which runs until the next space or >, so the closing " becomes part of the value. The validator reports this case twice, once with this message and once as “"” in an unquoted attribute value. When the value opens with a single quote and closes with a double quote, it runs until the next single quote, and the " again lands inside it.
Browsers parse width leniently and read 200" as 200, so the image often looks fine. A value that starts with the quote, such as "200", fails to parse, and the browser ignores it. The image then gets no reserved space before it loads, and the content below it shifts once it arrives.
Templates and string-built HTML cause most of these, for example width=<%= width %>" with the opening quote left out. Put matching double quotes around the number.
Invalid example
<img src="photo.jpg" alt="A red car" width=200" height="150">
<img src="photo.jpg" alt="A red car" width='200"' height="150">
Valid example
<img src="photo.jpg" alt="A red car" width="200" height="150">
The width and height attributes of an <img> take a number of pixels written with digits only, and the validator reports the first character in the value that isn't a digit.
Both attributes must hold a valid non-negative integer, such as 640. Units, percentages, signs, decimals, spaces and any other text make the value invalid. The character in the message tells you where the number broke: in 324&height=303 it's the &, in 10em it's the e, in -1 it's the -, and in " 300" it's the leading space.
Values like these usually come from code, not from hand-written markup. A template that copies the image's query string (?width=324&height=303) into the attribute, a CMS that pastes a CSS declaration into it, or a placeholder such as {{ width }} that was never filled in all end up here. Browsers keep the leading digits and drop the rest, so 10em becomes 10 pixels, not 10 em, and a value that doesn't start with a digit is ignored. Either way the browser may reserve the wrong space for the image, and the page shifts when it loads.
Write the pixel size on its own, with no unit. When the image should display at another size, or scale with the layout, set that in CSS and keep the attributes at the image's real pixel dimensions, so the browser still knows its aspect ratio.
Invalid example
<img src="photo.jpg" alt="A red car" width="324&height=303">
<img src="logo.png" alt="Company logo" width="10em" height="4em">
Valid example
<img src="photo.jpg" alt="A red car" width="324" height="303">
<img src="logo.png" alt="Company logo" width="160" height="64" style="width: 10em; height: auto;">
Why This Matters
While HTML5 is quite permissive with id values (allowing almost anything except spaces), elements within XML-based vocabularies like SVG and MathML are held to stricter rules. When these elements appear in your HTML document, their attributes must still conform to XML 1.0 naming conventions as defined by the relevant specification.
XML 1.0 names must follow these rules:
- Must start with a letter (
a–z,A–Z) or an underscore (_) - Subsequent characters can be letters, digits (
0–9), hyphens (-), underscores (_), and periods (.) - Cannot contain spaces, colons (outside of namespaced contexts), or special characters like
@,#,$,!, etc.
This error typically appears when design tools (such as Figma, Illustrator, or Sketch) export SVG files with auto-generated id values that include spaces or other invalid characters. Browsers may still render the content, but relying on non-conformant names can cause problems with CSS selectors, JavaScript's getElementById(), URL fragment references, and accessibility tools that depend on valid identifiers.
How to Fix It
- Remove spaces — replace them with hyphens or underscores, or use camelCase.
- Ensure the name starts with a letter or underscore — if it starts with a digit, prefix it with a letter or underscore.
- Strip out special characters — remove or replace characters like
@,#,(,), etc. - Review exported SVG files — if you're embedding SVGs from design tools, clean up the generated
idvalues before adding them to your HTML.
Examples
Invalid: Space in the id value
The space in "Group 270" makes this an invalid XML 1.0 name:
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<g id="Group 270">
<circle cx="50" cy="50" r="40" />
</g>
</svg>
Invalid: Name starts with a digit
XML 1.0 names cannot begin with a number:
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<rect id="1st-rectangle" width="100" height="50" />
</svg>
Invalid: Special characters in the name
Characters like ( and ) are not allowed:
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
<path id="icon(home)" d="M10 80 L50 10 L90 80 Z" />
</svg>
Fixed: Valid XML 1.0 names
Replace spaces with hyphens, prefix digit-leading names with a letter, and remove special characters:
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
<g id="group-270">
<circle cx="50" cy="50" r="40" />
</g>
<rect id="first-rectangle" width="100" height="50" />
<path id="icon-home" d="M10 80 L50 10 L90 80 Z" />
</svg>
Tip: Cleaning up exported SVGs
Design tools often produce id values like "Frame 42", "Vector (Stroke)", or "123_layer". A quick find-and-replace workflow can fix these before they land in your codebase. You can also use tools like SVGO to optimize and clean up SVG output, including stripping or renaming invalid identifiers.
max-height takes none, a length, a percentage or a sizing keyword such as fit-content, and the validator rejects anything else, including auto.
auto is valid for height and min-height, so it's easy to carry it over to max-height. That property has no automatic value. Its initial value is none, meaning no limit, and a browser that reads max-height: auto drops the declaration as invalid.
That matters when auto is meant to undo a limit from another rule, such as a collapsed panel with max-height: 0 that opens when a class is added, or a fixed cap that a media query should lift. The browser skips the auto, the earlier value still applies, and the content remains clipped. Write none to remove the limit.
Made-up keywords such as full get the same message. Besides none, the property accepts lengths like 300px or 80vh, percentages of the containing block's height, the keywords min-content, max-content and fit-content, and global keywords such as inherit and initial.
Invalid example
<style>
.panel {
max-height: 0;
overflow: hidden;
}
.panel.is-open {
max-height: auto;
}
</style>
Valid example
<style>
.panel {
max-height: 0;
overflow: hidden;
}
.panel.is-open {
max-height: none;
}
</style>
The text-autospace declaration uses a value the CSS standard does not define, most often none, which the standard calls no-autospace.
text-autospace controls the extra space a browser adds where Chinese, Japanese or Korean (CJK) characters meet Latin letters or digits. CSS Text Module Level 4 accepts normal, auto, no-autospace, or a combination of ideograph-alpha, ideograph-numeric and punctuation, optionally followed by insert or replace. The validator rejects any other value.
The none value usually comes from Microsoft Word, which writes text-autospace: none into the inline styles of the text it exports or copies. The declaration survives when that text is pasted into a CMS editor. It is a leftover from Internet Explorer's version of the property, whose ideograph-parenthesis and ideograph-space values are not standard either.
Browsers drop a declaration with an unknown value, so text-autospace: none has no effect and you can delete it without changing how the page looks. If the text mixes CJK and Latin characters and you want the spacing turned off, write no-autospace instead.
Invalid example
<p style="text-autospace: none;">Annual report 2026</p>
Valid example
Delete the declaration:
<p>Annual report 2026</p>
Or, to keep the spacing off in CJK text, use the standard keyword:
<p lang="ja" style="text-autospace: no-autospace;">HTML5とCSS3の基本</p>
The validator only accepts text-emphasis-position as a pair of keywords, over or under together with right or left, so a single keyword such as over is rejected.
text-emphasis-position sets where the emphasis marks drawn by text-emphasis go. These marks are small dots, circles or other shapes placed next to each character, mostly in Chinese, Japanese and Korean text. over and under put them above or below the line in horizontal text, and right and left put them on one side of the line in vertical text.
The current CSS Text Decoration Module Level 3 makes the right or left keyword optional and defaults it to right, so over on its own means the same as over right. The CSS checker inside the validator still follows the older grammar, which required both keywords. It reports a lone over or under, and any value that isn't one of those four keywords.
A lone over often comes from content copied out of a browser or an online word processor that pasted every computed style into a style attribute. In that case the element doesn't use emphasis marks at all, and over right is the property's initial value, so you can delete the declaration without changing how the page looks. If the element does draw emphasis marks, write both keywords: over right renders the same as over.
Invalid example
<p>
<span style="font-weight: 700; text-emphasis-position: over;">Opening hours</span>
</p>
Valid example
Delete the declaration when the element has no emphasis marks:
<p>
<span style="font-weight: 700;">Opening hours</span>
</p>
Or write both keywords when it does:
<p>
<span style="text-emphasis: filled dot; text-emphasis-position: over right;">Opening hours</span>
</p>
The text-transform CSS property controls the capitalization of text within an element. It's commonly used to enforce consistent text casing — for example, making headings appear in all uppercase or ensuring navigation links are lowercase — without changing the actual content in the HTML. When the validator encounters a value it doesn't recognize for this property, it flags it as invalid.
This error can occur for several reasons:
- Typos — writing
upppercaseinstead ofuppercase, orCapitalizeinstead ofcapitalize(CSS values are case-sensitive in validation contexts). - Incorrect values — using values from other properties, like
bold,italic, orcenter, which don't apply totext-transform. - Non-standard values — using browser-specific or experimental values that aren't part of the CSS specification.
- Wrong property — confusing
text-transformwithtext-decoration,text-align, orfont-variant, and using their values here instead.
Fixing this matters because invalid CSS can lead to unpredictable rendering across browsers. While most browsers will simply ignore an invalid declaration, your intended styling won't be applied, potentially breaking your design. Keeping your CSS valid also improves maintainability and ensures forward compatibility.
Valid values for text-transform
| Value | Effect |
|---|---|
none | No capitalization change (default) |
capitalize | First letter of each word is uppercased |
uppercase | All characters are converted to uppercase |
lowercase | All characters are converted to lowercase |
full-width | Forces characters into a full-width form (useful for CJK typography) |
full-size-kana | Converts small kana characters to full-size equivalents |
Examples
Incorrect — invalid value
In this example, bold is not a valid text-transform value. It likely belongs on the font-weight property instead.
<p style="text-transform: bold;">Welcome to our site</p>
Similarly, a simple typo will trigger this error:
<p style="text-transform: uppercse;">Welcome to our site</p>
Correct — using valid values
<p style="text-transform: uppercase;">Welcome to our site</p>
<p style="text-transform: capitalize;">Welcome to our site</p>
Correct — separating concerns with the right properties
If you intended to make text bold and uppercase, use the appropriate property for each effect:
<p style="font-weight: bold; text-transform: uppercase;">Welcome to our site</p>
Correct — using text-transform in a stylesheet
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Text Transform Example</title>
<style>
.heading {
text-transform: uppercase;
}
.name {
text-transform: capitalize;
}
.code-snippet {
text-transform: none;
}
</style>
</head>
<body>
<h1 class="heading">site navigation</h1>
<p class="name">john doe</p>
<code class="code-snippet">myVariable</code>
</body>
</html>
If you're unsure which value you need, uppercase and capitalize are the most commonly used. Use none when you need to override a text-transform rule inherited from a parent element.
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.
1K Weekly
1,000 monthly checks. Cancel anytime.
Get 1K Weekly →Join teams across 40+ countries