Adding JavaScript to a Page

JavaScript reaches a web page through the <script> element. You can write code directly inside it or, more commonly, point it at a separate .js file. Where you put the tag, and which attributes you give it, decides when the code runs.

Inline scripts

Code can go straight between <script> tags:

HTML index.html
<!DOCTYPE html>
<html>
<body>
  <h1 id="title">Welcome</h1>

  <script>
    document.querySelector("#title").textContent = "Welcome back!";
  </script>
</body>
</html>

This is handy for tiny snippets, but it mixes behaviour into your HTML and can't be cached or reused across pages.

External script files

For anything real, put the code in its own file and link to it with src:

HTML index.html
<script src="app.js"></script>
JS app.js
document.querySelector("#title").textContent = "Welcome back!";

External files keep HTML and JavaScript separate, can be shared between pages, and are cached by the browser so returning visitors don't download them again. The path in src works like any other link: relative (js/app.js), root-relative (/js/app.js) or a full URL.

Note: a <script> with a src attribute ignores any code written between its tags. Use two separate tags if you need both.

When does the script run?

By default, the browser reads HTML from top to bottom. When it reaches a <script>, it stops building the page, downloads and runs the script, and only then continues. That causes two problems for scripts in the <head>:

  1. The page appears more slowly, because rendering is blocked.
  2. The script can't find elements that come later in the HTML — they don't exist yet.

There are three common solutions:

ApproachHowRuns
Script at the end of <body><script src="app.js"></script> just before </body>After the HTML above it is built
defer<script src="app.js" defer> in the <head>After the whole page is parsed, in order
type="module"<script type="module" src="app.js">Like defer, and enables import/export

The modern recommendation is defer (or type="module") in the <head>: the browser downloads the file while it keeps building the page, then runs it once the HTML is ready.

HTML index.html
<head>
  <meta charset="UTF-8">
  <title>My page</title>
  <script src="app.js" defer></script>
</head>

async scripts

async also downloads without blocking, but runs the script the moment it arrives — possibly before the page is finished, and in no particular order relative to other scripts. It suits independent scripts such as analytics, but not code that touches the page or depends on another script.

Waiting for the page in code

If you can't control the script tag, you can wait for the page inside your code with the DOMContentLoaded event:

JS app.js
document.addEventListener("DOMContentLoaded", () => {
  document.querySelector("#title").textContent = "Ready!";
});

Running JavaScript outside a page

You don't always need an HTML file. Two quick alternatives:

  • The browser console — open developer tools (F12), choose the Console tab and type code directly. Great for experiments.
  • Node.js — install it from nodejs.org, save code in hello.js and run node hello.js in a terminal.
$ terminal
node hello.js

The examples on this site that don't touch the page run the same way in either environment.