HTML Guides for type
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The HTML living standard defines that scripts with type="module" are always fetched in parallel and evaluated after the document has been parsed, which is the same behavior that the defer attribute provides for classic scripts. Because this deferred execution is an inherent characteristic of module scripts, the spec explicitly forbids combining the two. Including both doesn’t change how the browser handles the script, but it signals a misunderstanding of how modules work and produces invalid HTML.
This validation error commonly arises when developers migrate classic scripts to ES modules. A classic script like <script defer src="app.js"></script> relies on the defer attribute to avoid blocking the parser. When converting to a module by adding type="module", it’s natural to leave defer in place — but it’s no longer needed or allowed.
It’s worth noting that the async attribute is valid on module scripts and does change their behavior. While defer is redundant because modules are already deferred, async overrides that default and causes the module to execute as soon as it and its dependencies have finished loading, rather than waiting for HTML parsing to complete.
How to Fix
Remove the defer attribute from any <script> element that has type="module". No other changes are needed — the loading and execution behavior will remain identical.
If you intentionally want the script to run as soon as possible (before parsing completes), use async instead of defer. But if you want the standard deferred behavior, simply omit both attributes and let the module default take effect.
Examples
❌ Incorrect: defer combined with type="module"
<script type="module" defer src="app.js"></script>
The defer attribute is redundant here and causes a validation error.
✅ Correct: module script without defer
<script type="module" src="app.js"></script>
Module scripts are deferred automatically, so this behaves exactly the same as the incorrect example above but is valid HTML.
✅ Correct: using async with a module (when needed)
<script type="module" async src="analytics.js"></script>
Unlike defer, the async attribute is permitted on module scripts. It causes the module to execute as soon as it’s ready, without waiting for HTML parsing to finish.
✅ Correct: classic script with defer
<script defer src="app.js"></script>
For classic (non-module) scripts, the defer attribute is valid and necessary if you want deferred execution.
The <script> element serves two distinct purposes in HTML: loading executable scripts and embedding non-executable data blocks. When the src attribute is present, the element is always being used to load an external script, so the type attribute must reflect a valid script type. Setting type to something like "text/html", "text/plain", or an invented value like "wrong" tells the browser this is not JavaScript, which means the external file referenced by src will be fetched but never executed — almost certainly not what the author intended.
The HTML specification restricts the allowed type values for <script src="..."> to three categories:
- An empty string (type=""): Treated the same as the default, which is JavaScript.
- A JavaScript MIME type: This includes text/javascript, application/javascript, and other legacy JavaScript MIME types. Since text/javascript is the default, specifying it is redundant.
- module: Indicates the script should be treated as a JavaScript module, enabling import/export syntax and deferred execution by default.
Any value outside these categories — such as text/html, application/json, or a made-up string — is invalid when src is present.
Why this matters
Broken functionality: A non-JavaScript type on a <script> with src prevents the browser from executing the loaded file. The script is effectively dead code that still costs a network request.
Standards compliance: The HTML living standard explicitly forbids this combination. Validators flag it because it almost always indicates a mistake — either the wrong type was applied, or the src attribute was added by accident.
Maintainability: Future developers reading the code may be confused about whether the script is supposed to execute or serve as an inert data block. Keeping markup valid makes intent clear.
How to fix it
- Remove the type attribute entirely. This is the best approach for classic JavaScript. The default behavior is text/javascript, so no type is needed.
- Use type="module" if the script uses ES module syntax (import/export).
- If you intended a data block (e.g., embedding JSON or a template), remove the src attribute and place the content inline inside the <script> element instead. Data blocks with non-JavaScript types cannot use src.
Examples
Invalid: non-JavaScript types with src
These all trigger the validation error because the type value is not a JavaScript MIME type, an empty string, or "module":
<script type="text/html" src="template.html"></script>
<script type="application/json" src="data.json"></script>
<script type="text/plain" src="app.js"></script>
<script type="wrong" src="app.js"></script>
Valid: omitting the type attribute
The simplest and recommended fix for classic scripts — just drop type:
<script src="app.js"></script>
Valid: using a JavaScript MIME type
This is valid but redundant, since text/javascript is already the default. The validator may suggest omitting it:
<script type="text/javascript" src="app.js"></script>
Valid: using type="module"
Use this when the external script uses ES module syntax:
<script type="module" src="app.js"></script>
Valid: using an empty type attribute
An empty string is treated as the default. It’s valid but unnecessary, and the validator may suggest removing it:
<script type="" src="app.js"></script>
Valid: data blocks without src
If you need a non-JavaScript type for an inline data block, remove the src attribute and place the content directly inside the element:
<script type="application/json" id="config">
{
"apiUrl": "https://example.com/api",
"debug": false
}
</script>
The <picture> element exists to give browsers a choice between multiple image sources. The browser evaluates each <source> in order, looking for the first one whose conditions match the current environment. These conditions are expressed through the media attribute (e.g., viewport width or resolution) and the type attribute (e.g., image/webp or image/avif). If a <source> lacks both attributes, it acts as an unconditional match — the browser will always select it, making any subsequent <source> elements or an <img> with srcset unreachable. This defeats the purpose of the <picture> element entirely.
The HTML specification requires these attributes specifically to prevent this situation. When a <source> has a following sibling <source> or a following <img> with srcset, at least one selection criterion (media or type) must be present so the browser can meaningfully choose between the options. A <source> without these attributes is only valid if it’s the last <source> before a plain <img> (one without srcset), since in that case it serves as the final fallback within the <picture>.
This matters for several reasons:
- Standards compliance: The HTML living standard explicitly defines this requirement. Violating it produces a validation error.
- Predictable rendering: Without distinguishing attributes, browsers may silently ignore sources or always pick the first one, leading to inconsistent behavior across browsers.
- Performance: The <picture> element is often used to serve smaller images on small viewports or modern formats like WebP and AVIF to browsers that support them. Without proper media or type attributes, these optimizations won’t work as intended.
How to fix it
Add a media attribute, a type attribute, or both to each <source> element that is followed by another <source> or an <img> with srcset:
- Use type when you’re offering the same image in different formats (e.g., AVIF, WebP, JPEG). The browser picks the first format it supports.
- Use media when you’re serving different images based on viewport conditions (art direction). The browser picks the source whose media query matches.
- Use both when you want to combine format negotiation with art direction.
Examples
Incorrect — <source> without media or type
Each <source> below has no selection criterion, so the browser has no way to choose between them:
<picture>
<source srcset="hero.webp">
<source srcset="hero.jpg">
<img src="hero.jpg" srcset="hero-2x.jpg 2x" alt="A mountain landscape">
</picture>
Correct — using type for format negotiation
Adding type lets the browser pick the first format it supports:
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" srcset="hero-2x.jpg 2x" alt="A mountain landscape">
</picture>
Correct — using media for art direction
Adding media lets the browser pick the source that matches the viewport:
<picture>
<source srcset="hero-wide.jpg" media="(min-width: 1024px)">
<source srcset="hero-narrow.jpg" media="(max-width: 1023px)">
<img src="hero-narrow.jpg" srcset="hero-narrow-2x.jpg 2x" alt="A mountain landscape">
</picture>
Correct — combining media and type
You can use both attributes together to serve the right format at the right viewport size:
<picture>
<source srcset="hero-wide.avif" media="(min-width: 1024px)" type="image/avif">
<source srcset="hero-wide.webp" media="(min-width: 1024px)" type="image/webp">
<source srcset="hero-narrow.avif" media="(max-width: 1023px)" type="image/avif">
<source srcset="hero-narrow.webp" media="(max-width: 1023px)" type="image/webp">
<img src="hero-narrow.jpg" alt="A mountain landscape">
</picture>
Correct — single <source> before a plain <img>
When there’s only one <source> and the <img> has no srcset, no media or type is required — but adding type is still recommended for clarity:
<picture>
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="A mountain landscape">
</picture>
The type attribute is specific to the <input> element, where it determines the kind of input control rendered — such as text, checkbox, email, or number. The <textarea> element serves a single, distinct purpose: providing a multi-line plain-text editing area. Because it doesn’t have multiple modes of operation, the HTML specification does not define a type attribute for it.
This error commonly occurs when developers confuse <textarea> with <input>, or when refactoring a single-line <input type="text"> into a multi-line <textarea> without removing the now-invalid type attribute. It can also appear when using templating systems or frameworks that apply attributes generically across different form elements.
While browsers will typically ignore the unrecognized type attribute on a <textarea>, keeping it in your markup causes W3C validation errors and can lead to confusion for other developers reading the code. Invalid attributes may also interfere with CSS attribute selectors (e.g., textarea[type="text"] is a selector targeting invalid markup), accessibility tools, or automated testing systems that rely on well-formed HTML.
To fix this issue, remove the type attribute from the <textarea> element. If you need to differentiate between multiple textareas, use id, name, or class attributes instead. If you actually need a single-line text input, use <input type="text"> rather than <textarea>.
Examples
Incorrect: type attribute on <textarea>
<label for="comment">Your comment:</label>
<textarea type="text" id="comment" name="comment" rows="4" cols="50"></textarea>
The type="text" attribute is not valid on <textarea> and will trigger a validation error.
Correct: <textarea> without type
<label for="comment">Your comment:</label>
<textarea id="comment" name="comment" rows="4" cols="50"></textarea>
Simply removing the type attribute resolves the issue. The <textarea> element inherently provides a multi-line text input, so no type is needed.
Correct: Using <input> when a single-line field is intended
If you intended a single-line text field, use <input> instead:
<label for="username">Username:</label>
<input type="text" id="username" name="username">
The type attribute is valid and expected on <input> elements, where it controls the type of input control rendered.
The datetime input type was originally proposed to allow users to enter a date and time along with a timezone. However, no browser ever fully implemented it with a usable UI, and the WHATWG HTML Living Standard officially dropped it. Because datetime is not a recognized value for the type attribute, browsers treat <input type="datetime"> as <input type="text"> — a plain text field with no built-in date or time validation, no native picker, and no semantic meaning for assistive technologies.
This matters for several reasons. From an accessibility standpoint, screen readers and other assistive technologies rely on the correct type attribute to communicate the purpose of an input to users. A fallback to type="text" provides no such context. From a validation and user experience perspective, native date/time input types offer built-in pickers on mobile and desktop browsers, enforce format constraints, and support attributes like min, max, and step — none of which work correctly when the type falls back to plain text. From a standards compliance perspective, using an obsolete type means your HTML is invalid, which can cause issues with automated testing, SEO audits, and quality assurance processes.
How to Fix It
Choose a replacement based on what data you need to collect:
- type="datetime-local" — Collects both a date and a time without timezone information. This is the most direct replacement for the old datetime type.
- type="date" — Collects only a date (year, month, day).
- type="time" — Collects only a time (hours, minutes, optionally seconds).
- type="text" with a JavaScript widget — Use this approach if you need timezone-aware datetime input, since no native HTML input type currently handles timezones.
The datetime-local input supports useful attributes like min, max, step, value, and name, giving you control over the range and granularity of selectable values. The step attribute is specified in seconds (e.g., step="60" for one-minute intervals, step="1" to allow seconds).
Examples
❌ Invalid: Using the obsolete datetime type
This triggers the W3C validation error:
<form>
<label>
Meeting:
<input type="datetime" name="meeting">
</label>
</form>
✅ Fixed: Using datetime-local
Replace datetime with datetime-local to collect both a date and time:
<form>
<label>
Meeting:
<input type="datetime-local" name="meeting" step="60">
</label>
</form>
✅ Fixed: Using separate date and time inputs
If you prefer to collect the date and time independently, split them into two fields:
<form>
<label>
Meeting date:
<input type="date" name="meeting-date" min="2025-01-01" max="2025-12-31">
</label>
<label>
Meeting time:
<input type="time" name="meeting-time" step="900">
</label>
</form>
In this example, step="900" on the time input sets 15-minute intervals (900 seconds).
✅ Fixed: Using datetime-local with constraints
You can set minimum and maximum allowed values using the standard datetime-local format (YYYY-MM-DDThh:mm):
<form>
<label>
Appointment:
<input
type="datetime-local"
name="appointment"
min="2025-06-01T09:00"
max="2025-06-30T17:00"
step="1800"
required>
</label>
<button type="submit">Book</button>
</form>
This restricts selection to June 2025 during business hours, in 30-minute increments, and makes the field required.
The HTML <input> element’s type attribute only accepts a specific set of predefined values defined in the HTML specification. These include values like text, password, email, number, date, datetime-local, checkbox, radio, and others. The value dob — presumably short for “date of birth” — is not among them.
When a browser encounters an invalid type value, it doesn’t throw an error or prevent the page from loading. Instead, it treats the input as type="text". This means the input might appear to work, but you lose important benefits: there’s no native date picker UI, no built-in date format validation, and no appropriate mobile keyboard. The W3C validator flags this to help you catch the mistake early.
This matters for several reasons:
- Accessibility: Valid input types provide semantic meaning to assistive technologies. A type="date" input tells screen readers that a date is expected, enabling better guidance for users.
- User experience: Native date inputs offer platform-appropriate date pickers on mobile and desktop, reducing input errors.
- Standards compliance: Using invalid attribute values produces unpredictable behavior across browsers and can break future compatibility.
To fix this issue, replace type="dob" with a recognized type. For a date of birth field, type="date" is the most appropriate choice. If you need more control over formatting, you can use type="text" with a JavaScript date picker library or custom validation.
Examples
❌ Invalid: using type="dob"
<label for="dob">Date of Birth:</label>
<input type="dob" id="dob" name="dob">
The browser will treat this as a plain text input, and the W3C validator will report: Bad value “dob” for attribute “type” on element “input”.
✅ Fixed: using type="date"
<label for="dob">Date of Birth:</label>
<input type="date" id="dob" name="dob">
This uses the native HTML date input, which provides a built-in date picker in most modern browsers. You can also constrain the date range with min and max attributes:
<label for="dob">Date of Birth:</label>
<input type="date" id="dob" name="dob" min="1900-01-01" max="2025-12-31">
✅ Fixed: using type="text" with a JavaScript date picker
If you need more control over the date picker’s appearance or need to support older browsers that lack native date input support, use type="text" and enhance it with JavaScript:
<label for="dob">Date of Birth:</label>
<input type="text" id="dob" name="dob" placeholder="YYYY-MM-DD">
You can then attach a JavaScript date picker library (such as Flatpickr, Pikaday, or a framework-specific component) to this input for a custom date selection experience. When using this approach, make sure to add appropriate aria-* attributes and validation to maintain accessibility.
Valid type values for reference
Here are some commonly used valid type values for the <input> element:
- text — plain text input
- date — date picker (year, month, day)
- datetime-local — date and time picker (no timezone)
- month — month and year picker
- number — numeric input
- email — email address input
- tel — telephone number input
- password — masked text input
Always choose the type that best matches the data you’re collecting. For a date of birth, type="date" is the most semantically correct and user-friendly option.
MIME types (also called media types) follow a strict type/subtype structure as defined by IETF standards. For example, image/png has the type image and the subtype png. The value "favicon" doesn’t follow this format — it has no slash and no subtype — so the validator reports “Subtype missing.” This is a common mistake that happens when developers confuse the purpose of the icon (a favicon) with the format of the file (an image in a specific encoding).
While most browsers are forgiving and will still display the favicon even with an invalid type value, using incorrect MIME types can cause issues. Some browsers or tools may ignore the <link> element entirely if the type doesn’t match a recognized format. It also hurts standards compliance and makes your HTML less predictable across different environments.
The correct MIME type depends on the file format of your favicon:
- .ico files: image/x-icon (or image/vnd.microsoft.icon)
- .png files: image/png
- .svg files: image/svg+xml
- .gif files: image/gif
It’s also worth noting that the type attribute on <link rel="icon"> is entirely optional. If omitted, the browser will determine the file type from the server’s Content-Type header or by inspecting the file itself. Removing it is a perfectly valid fix.
Examples
❌ Invalid: using “favicon” as the type
<link rel="icon" href="/favicon.png" type="favicon">
The value "favicon" is not a valid MIME type, triggering the validation error.
✅ Fixed: using the correct MIME type for a PNG favicon
<link rel="icon" href="/favicon.png" type="image/png">
✅ Fixed: using the correct MIME type for an ICO favicon
<link rel="icon" href="/favicon.ico" type="image/x-icon">
✅ Fixed: using the correct MIME type for an SVG favicon
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
✅ Fixed: omitting the type attribute entirely
<link rel="icon" href="/favicon.png">
Since the type attribute is optional for <link rel="icon">, removing it avoids the error and lets the browser detect the format automatically. This is often the simplest and most maintainable approach.
The type attribute on an anchor (<a>) element is an advisory hint that tells the browser what kind of content to expect at the link destination. According to the WHATWG HTML specification, when present, this attribute must contain a valid MIME type string. An empty string ("") is not a valid MIME type, so the W3C validator flags it as an error.
This issue commonly appears when a CMS, templating engine, or JavaScript framework generates the type attribute dynamically but produces an empty value when no MIME type is available. It can also happen when developers add the attribute as a placeholder intending to fill it in later.
Why this matters
While browsers generally handle an empty type attribute gracefully by ignoring it, there are good reasons to fix this:
- Standards compliance — An empty string violates the HTML specification’s requirement for a valid MIME type, making your document invalid.
- Accessibility — Assistive technologies may use the type attribute to communicate the linked resource’s format to users. An empty value provides no useful information and could lead to unexpected behavior in some screen readers.
- Predictable behavior — Browsers are allowed to use the type hint to influence how they handle a link (e.g., suggesting a download or choosing a handler). An empty value makes the intent ambiguous.
How to fix it
You have two straightforward options:
- Remove the type attribute — If you don’t need to specify the MIME type, simply omit the attribute. This is the preferred approach when the type is unknown or unnecessary.
- Provide a valid MIME type — If you want to hint at the linked resource’s format, supply a proper MIME type string like application/pdf, text/html, image/png, application/zip, etc.
The type attribute is purely advisory — the browser does not enforce it or refuse to follow the link if the actual content type differs. So omitting it is always safe.
Examples
Incorrect — empty type attribute
<a href="report.pdf" type="">Download Report</a>
This triggers the validation error because "" is not a valid MIME type.
Correct — attribute removed
<a href="report.pdf">Download Report</a>
Removing the type attribute entirely is the simplest fix and works perfectly when the MIME type hint isn’t needed.
Correct — valid MIME type provided
<a href="report.pdf" type="application/pdf">Download Report</a>
If you want to explicitly indicate the format of the linked resource, use a proper MIME type value.
Multiple links with correct type usage
<ul>
<li><a href="slides.pptx" type="application/vnd.openxmlformats-officedocument.presentationml.presentation">Slides (PPTX)</a></li>
<li><a href="data.csv" type="text/csv">Data (CSV)</a></li>
<li><a href="https://example.com/about">About Us</a></li>
</ul>
In this example, the first two links include type attributes with valid MIME types to hint at the file format. The third link, pointing to a regular webpage, omits type entirely since it’s not needed.
Fixing dynamically generated attributes
If your template engine produces empty type attributes, add a conditional check:
<!-- Instead of always outputting type="" -->
<!-- Only include the attribute when a value exists -->
<a href="report.pdf" type="application/pdf">Download Report</a>
In template logic, ensure you only render the type attribute when a non-empty MIME type value is available. Otherwise, omit the attribute from the output altogether.
The type attribute on a <link> element must contain a single MIME type, not a comma-separated list of multiple types.
The type attribute specifies the MIME type of the linked resource and only accepts one value. It helps the browser decide whether it can handle the resource before downloading it. If you want to reference a favicon that could be in PNG or ICO format, you should pick the single correct MIME type that matches the actual file you’re linking to.
For .png favicons, use image/png. For .ico favicons, use image/x-icon. If you need to support both formats, use separate <link> elements — one for each file.
Invalid Example
<link rel="icon" type="image/png, image/x-icon" href="/favicon.png">
Valid Examples
If your favicon is a PNG file:
<link rel="icon" type="image/png" href="/favicon.png">
If you want to provide both formats, use two separate <link> elements:
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
The browser will select the most appropriate icon from the available options. Most modern browsers prefer PNG, while older browsers will fall back to ICO.
The HTML <input> element accepts a specific set of values for its type attribute, as defined by the HTML specification. The value "numeric" is not one of them. When a browser encounters an unrecognized type value, it falls back to type="text", meaning the user gets a plain text field instead of a dedicated numeric input. This fallback behavior means you lose built-in features like increment/decrement spinner controls, numeric keyboard on mobile devices, and native client-side validation that rejects non-numeric entries.
This confusion often arises because of the inputmode="numeric" attribute, which is valid and controls which virtual keyboard appears on mobile devices. The inputmode attribute and the type attribute serve different purposes, and mixing them up leads to this validation error.
Using the correct type="number" value matters for several reasons:
- Accessibility: Screen readers and assistive technologies use the type attribute to announce the expected input format to users.
- User experience: Browsers display appropriate controls (spinners, numeric keypads) for type="number" inputs.
- Validation: Native form validation automatically checks that the entered value is a valid number, within optional min/max bounds and matching an optional step value.
- Standards compliance: Invalid type values cause W3C validation errors and signal potential bugs in your markup.
Examples
Incorrect: using type="numeric"
This triggers the validation error because "numeric" is not a valid type value:
<label for="quantity">Quantity:</label>
<input type="numeric" id="quantity" name="quantity">
The browser will treat this as type="text", so users can type any characters, no spinner controls appear, and no numeric validation occurs.
Correct: using type="number"
Replace "numeric" with "number":
<label for="quantity">Quantity:</label>
<input type="number" id="quantity" name="quantity" min="1" max="10">
This gives you a proper numeric input with optional min, max, and step attributes for constraining the allowed range and increments.
Alternative: using inputmode="numeric" with type="text"
If you need a numeric keyboard on mobile but want more control over the input (for example, accepting values like zip codes or credit card numbers that aren’t truly “numbers”), you can use inputmode="numeric" on a text input instead:
<label for="zip">ZIP Code:</label>
<input type="text" inputmode="numeric" pattern="[0-9]{5}" id="zip" name="zip">
Here, type="text" is valid, inputmode="numeric" triggers the numeric keyboard on mobile devices, and the pattern attribute provides validation. This approach is useful when type="number" isn’t appropriate — for instance, type="number" strips leading zeros and allows scientific notation like 1e5, which is undesirable for codes and identifiers.
Summary of the fix
| Before (invalid) | After (valid) | Use case |
|---|---|---|
| type="numeric" | type="number" | Actual numeric values (quantities, prices, ages) |
| type="numeric" | type="text" inputmode="numeric" | Numeric-looking codes (ZIP, PIN, credit card) |
In most cases, simply changing type="numeric" to type="number" is the correct fix. Choose the inputmode approach only when you specifically need a text field with a numeric keyboard.
Understanding the Issue
MIME types follow a specific format: a type and a subtype separated by a forward slash, such as text/javascript or application/json. When the W3C validator encounters type="rocketlazyloadscript" on a <script> element, it flags it because this value has no slash and no subtype — it doesn’t conform to the MIME type syntax defined in the HTML specification.
The value rocketlazyloadscript is intentionally set by the WP Rocket WordPress caching and performance plugin. WP Rocket changes the type attribute of <script> elements from text/javascript (or removes the default) and replaces it with this custom value. This prevents the browser from executing the script immediately on page load. WP Rocket’s JavaScript then swaps the type back to a valid value when the script should actually be loaded, achieving a lazy-loading effect that can improve page performance.
Why This Is Flagged
The HTML specification states that if the type attribute is present on a <script> element, its value must be one of the following:
- A valid JavaScript MIME type (e.g., text/javascript) — indicating the script should be executed.
- The string module — indicating the script is a JavaScript module.
- Any other valid MIME type that is not a JavaScript MIME type — indicating a data block that the browser should not execute.
Since rocketlazyloadscript is not a valid MIME type at all (it lacks the type/subtype structure), it fails validation. While browsers will simply ignore scripts with unrecognized type values (which is exactly what WP Rocket relies on), the markup itself is technically non-conforming.
How to Fix It
Because this value is generated by a plugin rather than authored manually, your options are:
-
Configure WP Rocket to exclude specific scripts — In WP Rocket’s settings under “File Optimization,” you can exclude individual scripts from the “Delay JavaScript execution” feature. This prevents WP Rocket from modifying their type attribute.
-
Disable delayed JavaScript execution entirely — If W3C compliance is critical, you can turn off the “Delay JavaScript execution” option in WP Rocket. This eliminates the validation errors but sacrifices the performance benefit.
-
Accept the validation errors — WP Rocket acknowledges these errors in their documentation and considers them an expected side effect of their optimization technique. Since browsers handle the non-standard type gracefully (by not executing the script), there is no functional or accessibility issue. The errors are purely a standards compliance concern.
Examples
Invalid: Non-standard type value (generated by WP Rocket)
<script type="rocketlazyloadscript" src="/js/analytics.js"></script>
The validator reports: Bad value “rocketlazyloadscript” for attribute “type” on element “script”: Subtype missing.
Valid: Standard type attribute
<script type="text/javascript" src="/js/analytics.js"></script>
Valid: Omitting the type attribute entirely
Since text/javascript is the default for <script> elements in HTML5, the type attribute can be omitted entirely:
<script src="/js/analytics.js"></script>
Valid: Using a module script
<script type="module" src="/js/app.js"></script>
Valid: Using a data block with a proper MIME type
If you need a non-executed data block, use a valid MIME type that isn’t a JavaScript type:
<script type="application/json" id="config">
{"lazy": true, "threshold": 200}
</script>
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/ pdf or application /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 type value — 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 type is 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 type attribute 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 type value 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/subtype value — for example, application/pdf rather than just application.
- If you used type to try to style or change the link’s behavior, remove the type attribute entirely. Use CSS for visual styling or switch to a more appropriate element like <button>.
- If you don’t need the type attribute, 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 <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 type attribute 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 type attribute 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 type contains a valid MIME type, not a URL or other string. Common valid values include text/css, image/png, image/x-icon, image/svg+xml, and application/rss+xml.
- Ensure URLs are in the href attribute, not type.
- Consider removing type entirely. For stylesheets, modern browsers default to text/css, so type="text/css" is optional. For many use cases, the type attribute 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">
A MIME type (also called a media type) is composed of two parts: a type and a subtype, separated by a forward slash (/) with no whitespace. For example, text/javascript has text as the type and javascript as the subtype. When you specify a value like text or javascript alone — without the slash and the other component — the validator reports this error because the subtype is missing.
This error commonly occurs when authors confuse the MIME type format with a simple label, writing something like type="text" or type="javascript" instead of the full type="text/javascript". It can also happen due to a typo, such as accidentally omitting the slash or the subtype portion.
Why this matters
Browsers rely on the type attribute to determine how to process the contents of a <script> element. An invalid MIME type can cause browsers to misinterpret or skip the script entirely. While modern browsers default to JavaScript when no type is specified, providing a malformed MIME type is not the same as omitting it — it may lead to unpredictable behavior across different browsers and versions. Keeping your markup valid also ensures better tooling support and forward compatibility.
How to fix it
You have two main options:
- Provide a complete, valid MIME type. For JavaScript, use text/javascript. For JSON data blocks, use application/json. For importmaps, use importmap.
- Remove the type attribute entirely. Per the HTML specification, the default type for <script> is text/javascript, so omitting type is perfectly valid and is actually the recommended approach for standard JavaScript.
Examples
Incorrect: missing subtype
<!-- "text" alone is not a valid MIME type -->
<script type="text" src="app.js"></script>
<!-- "javascript" alone is not a valid MIME type -->
<script type="javascript" src="app.js"></script>
Correct: full MIME type specified
<script type="text/javascript" src="app.js"></script>
Correct: omitting the type attribute (recommended for JavaScript)
<script src="app.js"></script>
Since text/javascript is the default, omitting the attribute is the cleanest approach for standard JavaScript files.
Correct: using type for non-JavaScript purposes
The type attribute is still useful when embedding non-JavaScript content in a <script> element. In these cases, always use the full MIME type:
<script type="application/json" id="config">
{"apiUrl": "https://example.com/api"}
</script>
<script type="importmap">
{ "imports": { "lodash": "/libs/lodash.js" } }
</script>
Common valid MIME types for <script>
| MIME Type | Purpose |
|---|---|
| text/javascript | Standard JavaScript (default) |
| module | JavaScript module |
| importmap | Import map |
| application/json | Embedded JSON data |
| application/ld+json | Linked Data / structured data |
Note that module and importmap are special values defined by the HTML specification and are not traditional MIME types, but they are valid values for the type attribute on <script> elements.
The HTML specification defines a specific set of valid values for the type attribute on <input> elements, including text, number, email, tel, url, date, password, search, hidden, checkbox, radio, file, submit, reset, button, image, range, color, and others. The value "zip" is not among them. When a browser encounters an unrecognized type value, it falls back to type="text" — so the input may appear to work, but the markup is invalid and you lose the opportunity to leverage built-in browser features for better user experience.
This matters for several reasons. Invalid HTML can cause unpredictable behavior across different browsers and assistive technologies. Screen readers and other tools rely on valid markup to convey the purpose of form controls to users. Additionally, using the correct combination of valid attributes allows browsers to show optimized keyboards on mobile devices (e.g., a numeric keypad for ZIP codes) and to autofill values intelligently.
For ZIP or postal code fields, the best approach is to use type="text" combined with the autocomplete="postal-code" attribute, which tells browsers exactly what kind of data is expected. You can further enhance the input with inputmode="numeric" to trigger a numeric keyboard on mobile devices (for purely numeric ZIP codes like in the US) and a pattern attribute for client-side validation.
Examples
❌ Invalid: Using type="zip"
<label for="zip">ZIP Code</label>
<input type="zip" id="zip" name="zip">
This triggers the validation error because "zip" is not a valid value for the type attribute.
✅ Valid: Using type="text" with appropriate attributes (US ZIP code)
<label for="zip">ZIP Code</label>
<input
type="text"
id="zip"
name="zip"
inputmode="numeric"
pattern="[0-9]{5}(-[0-9]{4})?"
autocomplete="postal-code"
placeholder="12345"
aria-describedby="zip-hint">
<span id="zip-hint">5-digit ZIP code (e.g., 12345 or 12345-6789)</span>
This approach uses type="text" to remain valid, inputmode="numeric" to prompt a numeric keyboard on mobile, pattern for client-side format validation, and autocomplete="postal-code" so browsers can autofill the field correctly.
✅ Valid: International postal code field
<label for="postal">Postal Code</label>
<input
type="text"
id="postal"
name="postal_code"
autocomplete="postal-code">
For international postal codes that may contain letters (e.g., UK, Canada), omit inputmode="numeric" and use a broader or no pattern, since formats vary widely by country.
Why not type="number"?
You might be tempted to use type="number" for ZIP codes, but this is discouraged. type="number" is designed for values that represent a quantity — it may strip leading zeros (turning “01234” into “1234”), add increment/decrement spinner buttons, and behave unexpectedly with non-numeric postal codes. Always use type="text" for ZIP and postal codes.
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 for checkbox and menuitemcheckbox roles 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 <object> element embeds external resources such as images, videos, PDFs, or other media into a page. The data attribute specifies the URL of the resource, while the type attribute declares its MIME type (e.g., "application/pdf", "image/svg+xml", "video/mp4"). According to the HTML specification, the element must have at least one of these attributes present — without either, the element is meaningless because the browser cannot determine what to fetch or how to render it.
While the validator requires at least one of these attributes, best practice is to include both. Here’s why:
- Without data, the browser has no resource to load.
- Without type, the browser must guess the content type from the server response, which can lead to incorrect rendering or security issues.
- With both, the browser knows exactly what to fetch and how to handle it before the resource even begins downloading, improving performance and reliability.
Including both attributes also benefits accessibility. Assistive technologies use the type attribute to determine how to present the content to users. Without it, screen readers and other tools may not be able to convey useful information about the embedded resource. You should also always provide fallback content inside the <object> element for browsers or devices that cannot render the embedded resource.
Examples
Missing both attributes (triggers the error)
<object width="600" height="400">
<p>Fallback content here.</p>
</object>
The validator reports this error because neither data nor type is present. The browser has no information about what this <object> should display.
Missing type attribute (valid but not recommended)
<object data="example.pdf" width="600" height="400">
<p>Your browser does not support PDFs. <a href="example.pdf">Download the PDF</a>.</p>
</object>
This passes validation because data is present, but the browser must determine the content type on its own. Adding type is strongly recommended.
Missing data attribute (valid but limited)
<object type="application/pdf" width="600" height="400">
<p>No PDF to display.</p>
</object>
This also passes validation since type is present, but without data there is no resource to load. This pattern is uncommon and generally not useful on its own.
Correct: both attributes provided
<object data="example.pdf" type="application/pdf" width="600" height="400">
<p>Your browser does not support PDFs. <a href="example.pdf">Download the PDF</a>.</p>
</object>
Correct: embedding an SVG image
<object data="diagram.svg" type="image/svg+xml" width="300" height="200">
<img src="diagram.png" alt="Architecture diagram showing the system components">
</object>
This example also demonstrates good fallback practice — if the browser cannot render the SVG via <object>, it falls back to a regular <img> element with descriptive alt text.
Correct: embedding a video
<object data="intro.mp4" type="video/mp4" width="640" height="360">
<p>Your browser cannot play this video. <a href="intro.mp4">Download it instead</a>.</p>
</object>
Quick reference of common MIME types
| Resource type | type value |
|---|---|
| PDF document | application/pdf |
| SVG image | image/svg+xml |
| MP4 video | video/mp4 |
| HTML page | text/html |
| Flash (legacy) | application/x-shockwave-flash |
To resolve this validation error, ensure every <object> element includes at least a data or type attribute. For the best results across browsers and assistive technologies, always provide both along with meaningful fallback content inside the element.
In earlier versions of HTML (HTML 4 and XHTML), the type attribute was required on the <style> element to declare the MIME type of the styling language being used. The value was almost always text/css, as CSS has been the dominant stylesheet language for the web since its inception.
With HTML5, the specification changed. The type attribute on <style> now defaults to text/css, and since no browser supports any other styling language, the attribute serves no practical purpose. The WHATWG HTML Living Standard explicitly notes that the attribute is unnecessary and can be omitted. The W3C validator flags its presence as a warning to encourage cleaner, more modern markup.
Why This Matters
- Cleaner code: Removing unnecessary attributes reduces file size (even if marginally) and improves readability. Every attribute should earn its place in your markup.
- Standards compliance: Modern HTML encourages omitting default values when they add no information. Including type="text/css" signals outdated coding practices.
- Consistency: The same principle applies to <script> elements, where type="text/javascript" is also unnecessary. Keeping your markup consistent by omitting both makes your codebase easier to maintain.
How to Fix It
The fix is straightforward: find every <style> element in your HTML that includes a type attribute and remove it. No other changes are needed — the browser behavior will be identical.
If you’re working on a large codebase, a simple search for <style type= across your files will help you find all instances.
Examples
❌ Incorrect: Redundant type attribute
<style type="text/css">
p {
color: red;
}
</style>
<p>This text will be red.</p>
The type="text/css" attribute is unnecessary and triggers the W3C validator warning.
✅ Correct: type attribute omitted
<style>
p {
color: red;
}
</style>
<p>This text will be red.</p>
Without the type attribute, the browser still interprets the contents as CSS — the behavior is exactly the same.
❌ Incorrect: Other variations that also trigger the warning
The warning is triggered regardless of how the type value is formatted:
<style type="text/css" media="screen">
body {
font-family: sans-serif;
}
</style>
✅ Correct: Other attributes are fine, just remove type
<style media="screen">
body {
font-family: sans-serif;
}
</style>
Note that other valid attributes like media or nonce should be kept — only the type attribute needs to be removed.
The <script> element’s type attribute specifies the MIME type of the script. In earlier HTML versions (HTML 4 and XHTML), the type attribute was required and authors had to explicitly declare type="text/javascript". However, the HTML5 specification changed this — JavaScript is now the default scripting language, so when the type attribute is omitted, browsers automatically treat the script as JavaScript.
Because of this default behavior, including type="text/javascript" (or variations like type="application/javascript") is unnecessary. The W3C HTML Validator raises a warning to encourage cleaner, more concise markup. While this isn’t an error that will break your page, removing the redundant attribute keeps your HTML lean and aligned with modern standards.
There are legitimate uses for the type attribute on <script> elements, such as type="module" for ES modules or type="application/ld+json" for structured data. These values change the behavior of the <script> element and should absolutely be kept. The validator only flags the attribute when its value is a JavaScript MIME type, since that’s already the default.
Examples
Incorrect — unnecessary type attribute
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript">
console.log("Hello, world!");
</script>
Correct — type attribute removed
<script src="app.js"></script>
<script>
console.log("Hello, world!");
</script>
Correct — type attribute used for non-default purposes
The type attribute is still necessary and valid when you’re using it for something other than plain JavaScript:
<!-- ES module -->
<script type="module" src="app.mjs"></script>
<!-- JSON-LD structured data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Example Inc."
}
</script>
<!-- Import map -->
<script type="importmap">
{
"imports": {
"utils": "./utils.js"
}
}
</script>
Quick fix checklist
- Search your HTML files for type="text/javascript" and type="application/javascript".
- Remove the type attribute from those <script> tags entirely.
- Leave the type attribute on any <script> tags that use type="module", type="importmap", type="application/ld+json", or other non-JavaScript MIME types.
The type attribute on the <menu> element is obsolete and should be removed.
The <menu> element was originally designed to support different types of menus, including type="context" for context menus and type="toolbar" for toolbars. These features were never widely implemented by browsers and have been removed from the HTML specification.
In the current HTML living standard, the <menu> element is simply a semantic alternative to <ul> for representing a list of interactive items or commands, such as a toolbar of buttons. It no longer accepts a type attribute.
If you need a custom context menu (right-click menu), the recommended approach is to use JavaScript to listen for the contextmenu event and display your own custom menu using standard HTML and CSS.
Invalid Example
<menu type="context" id="my-menu">
<menuitem label="Copy"></menuitem>
<menuitem label="Paste"></menuitem>
</menu>
Valid Example
Using <menu> as a simple list of commands:
<menu>
<li><button>Copy</button></li>
<li><button>Paste</button></li>
</menu>
If you need a custom context menu, handle it with JavaScript:
<div id="target">Right-click here</div>
<menu id="context-menu" style="display: none; position: absolute;">
<li><button>Copy</button></li>
<li><button>Paste</button></li>
</menu>
<script>
const target = document.getElementById("target");
const menu = document.getElementById("context-menu");
target.addEventListener("contextmenu", (e) => {
e.preventDefault();
menu.style.display = "block";
menu.style.left = e.pageX + "px";
menu.style.top = e.pageY + "px";
});
document.addEventListener("click", () => {
menu.style.display = "none";
});
</script>
Note that the <menuitem> element is also obsolete and no longer part of the HTML specification. Use standard elements like <button> or <a> inside <li> elements instead.
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