# Bad value “X” for attribute “async” on element “script”.

> Canonical HTML version: https://rocketvalidator.com/html-validation/bad-value-x-for-attribute-async-on-element-script
> Attribution: Rocket Validator (https://rocketvalidator.com)
> License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

The HTML specification defines boolean attributes as attributes whose presence indicates a `true` state and whose absence indicates `false`. According to the [WHATWG HTML standard](https://html.spec.whatwg.org/multipage/common-microsyntax.html#boolean-attributes), a boolean attribute may only have three valid representations:

- The attribute name alone (e.g., `async`)
- The attribute with an empty string value (e.g., `async=""`)
- The attribute with a value matching its own name, case-insensitively (e.g., `async="async"`)

Any other value — such as `async="true"`, `async="1"`, `async="yes"`, or `async="false"` — is invalid HTML and will trigger this validation error. This is a common misunderstanding because developers often assume boolean attributes work like boolean values in programming languages, where you'd assign `true` or `false`.

### Why this matters

While most browsers are lenient and will treat any value of `async` as the `true` state (since the attribute is present regardless of its value), using invalid values creates several problems:

- **Standards compliance**: Invalid HTML may cause issues with strict parsers, validators, or tools that process your markup.
- **Misleading intent**: Writing `async="false"` does **not** disable async behavior — the attribute is still present, so the browser treats it as enabled. This can lead to confusing bugs where a script behaves asynchronously even though the developer intended otherwise.
- **Maintainability**: Other developers reading the code may misinterpret `async="false"` as actually disabling async loading.

To disable async behavior, you must **remove the attribute entirely** rather than setting it to `"false"`.

### How `async` works

For **classic scripts** with a `src` attribute, the `async` attribute causes the script to be fetched in parallel with HTML parsing and executed as soon as it's available, without waiting for the document to finish parsing.

For **module scripts** (`type="module"`), the `async` attribute causes the module and all its dependencies to be fetched in parallel and executed as soon as they are ready, rather than waiting until the document has been parsed (which is the default deferred behavior for modules).

## Examples

### ❌ Invalid: arbitrary values on `async`

```html
<!-- Bad: "true" is not a valid boolean attribute value -->
<script async="true" src="app.js"></script>

<!-- Bad: "1" is not a valid boolean attribute value -->
<script async="1" src="analytics.js"></script>

<!-- Bad: "yes" is not a valid boolean attribute value -->
<script async="yes" src="tracker.js"></script>

<!-- Bad and misleading: this does NOT disable async -->
<script async="false" src="app.js"></script>
```

### ✅ Valid: correct boolean attribute usage

```html
<!-- Preferred: attribute name alone -->
<script async src="app.js"></script>

<!-- Also valid: empty string value -->
<script async="" src="app.js"></script>

<!-- Also valid: value matching attribute name -->
<script async="async" src="app.js"></script>

<!-- Correct way to disable async: remove the attribute -->
<script src="app.js"></script>
```

### ✅ Valid: `async` with module scripts

```html
<script async type="module" src="app.mjs"></script>

<script async type="module">
  import { init } from './utils.mjs';
  init();
</script>
```

This same rule applies to all boolean attributes in HTML, including `defer`, `disabled`, `checked`, `required`, `hidden`, and others. When in doubt, use the attribute name on its own with no value — it's the cleanest and most widely recognized form.
