The HTML nomodule attribute
Current browsers skip any classic script marked with the HTML nomodule attribute. Paired with <script type="module">, it gives browsers without module support a fallback, since they ignore the module as an unknown type and run the nomodule script instead.
Overview
The HTML nomodule attribute stops a classic script from running in current browsers, all of which support module scripts. It exists to mark fallback code for browsers that can't run modules.
It is half of a pair, such as <script type="module" src="app.js"> next to <script nomodule defer src="app-legacy.js">. A modern browser runs only the module. A browser without module support skips the module as an unknown script type and runs the fallback.
Under the HTML standard, a browser that skips the script doesn't download it either. The check for nomodule comes before the fetch step, so an external nomodule file is never requested and fires no load or error event. Inline scripts with nomodule are skipped the same way.
Safari 10.1 on macOS and 10.3 on iOS run both the module and the fallback, because they support module scripts but not nomodule, which arrived in version 11. The other engines added nomodule along with modules.
Syntax
<script type="module" src="app.js"></script>
<script nomodule defer src="app-legacy.js"></script>
Values
| Value |
|---|
| Browsers that support nomodule skip the classic script. |
Example
<p>This code holds a nomodule fallback and a module script.</p>
<div role="status"><ul id="log"></ul></div>
<p>In a current browser, only the module adds a line. Delete nomodule in the editor and the fallback adds one too.</p>
<script nomodule>
const fallbackItem = document.createElement('li');
fallbackItem.textContent = 'The nomodule fallback ran.';
document.getElementById('log').append(fallbackItem);
</script>
<script type="module">
const moduleItem = document.createElement('li');
moduleItem.textContent = 'The module script ran.';
document.getElementById('log').append(moduleItem);
</script>
Best practices
- Pair each
nomodulescript with a module script that loads the same features. On its own, a nomodule script runs only in old browsers, and modern ones get none of its code. - Add defer to the nomodule script. The fallback then runs after parsing, the same point at which module scripts run.
- Build the fallback without import or export statements. In a classic script, an import declaration throws a SyntaxError.
- Serve a cross-origin module with CORS headers. Module scripts need CORS for cross-origin fetches, and if the module fails, modern browsers have no fallback to run, since they skip the nomodule copy.























