<script> Script
Runs or loads JavaScript.
<script> runs JavaScript, written between the tags or loaded from a file through src. Even with src, it needs an empty closing tag. <script /> will not work.
A plain script blocks the page while it loads. defer runs it after the HTML has been parsed, and type="module" behaves that way by default. async runs it the moment it arrives, in no fixed order. The previews in this course do not run JavaScript.
The script element definition (opens in a new tab) includes a diagram comparing classic, async, defer and module scripts. The Linking CSS and JavaScript lesson covers how to link scripts.
Syntax
<script src="app.js" defer></script>When to use it
Live search results, a cart that updates without a reload, an interactive map: HTML cannot do these alone, and <script> fills the gap. Load an external file with src where you can. The browser caches it, and every page shares one copy. Inline scripts are for tiny bits of page-specific setup.
First check whether HTML already covers it. An accordion is a details element. Popups can be dialog or popover. Form validation runs on required and pattern. Each script you skip is one file fewer to download and one thing fewer to break.
Script can also carry data that never runs. With type="application/ld+json" it holds structured data for search engines, and any other non-JavaScript type is an inert data block. Inline code has one trap. The text </script> anywhere inside, even in a string, ends the element early and the rest spills onto the page. Escape it as <\/script>. The Linking CSS and JavaScript lesson covers loading.
Attributes
| Attribute | What it does |
|---|---|
src | URL of an external script. |
type | module for JavaScript modules, importmap for import maps. Omit for classic scripts. |
defer | Runs after the document is parsed, in order. |
async | Runs as soon as it downloads, without waiting. |
crossorigin | CORS mode for the request. |
integrity | Hash the file must match. |
nomodule | Runs only in browsers without module support. |
referrerpolicy | How much referrer information to send. |
Live example
Edit the code and watch the preview.
<p>The script below would log a message in the console.</p>
<script src="app.js" defer></script>
<script>
console.log('Hello from JavaScript');
</script>More examples
Structured data for search engines
The recipe page describes itself in JSON-LD, a data block browsers never run. Search engines read it and may show rich results; Google's introduction to structured data (opens in a new tab) has the details. Visitors see no difference on the page.
<h1>Fluffy pancakes</h1>
<img src="pancakes.svg" alt="A stack of pancakes" width="400" height="300">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Recipe",
"name": "Fluffy pancakes",
"recipeYield": "8 pancakes",
"totalTime": "PT20M"
}
</script>Module script with a fallback
A modern browser loads the module (deferred automatically) and ignores the script marked nomodule. A very old browser that has never heard of modules does the reverse. This preview runs no scripts, so all you get is the paragraph.
<p>The app loads below this line.</p>
<script type="module" src="app.js"></script>
<script nomodule src="app-legacy.js"></script>Tip: defer or type="module" keeps scripts from blocking the page.
Browser support
Every browser supports script, and the HTML Living Standard defines it. defer and async work everywhere today. JavaScript modules with type="module" have run in all major browsers since 2018 (module script support (opens in a new tab)). nomodule is there for very old browsers, and these days you will rarely need it.
Accessibility
Anything a script adds has to stay keyboard operable, and scripts must not move focus or change context without warning (WCAG 2.1.1, 3.2.1). Why focus should never trigger surprises is explained in the W3C note Understanding On Focus (opens in a new tab).
Common mistakes
Wrong
<script src="app.js" />Right
<script src="app.js" defer></script>script is not void. The browser ignores the self-closing slash and treats the markup after it as script.
Frequently asked questions
What is the difference between async and defer?
Neither one blocks HTML parsing while the script downloads. The difference is when it runs. defer scripts wait until the document is parsed and then run in order, which suits most page scripts. async scripts run as soon as they arrive, in any order, a good fit for independent scripts like analytics. Module scripts (type="module") defer by default. To try HTML, CSS and JavaScript together, open an online HTML, CSS and JS editor (opens in a new tab) with instant preview.
Should script tags go in the head or at the end of the body?
With defer or type="module", put them in the <head>. The browser finds them early and still runs them after parsing. Classic scripts without those attributes block rendering, which is why people used to place them right before </body>. Inline scripts always run on the spot. What each language is for is explained in the HTML vs CSS vs JavaScript guide.
Practise it
- Linking CSS and JavaScript (Module 7: Head and Metadata)