Where to Write JavaScript

The script tag, external files, and why defer matters.

Lesson 2 of 56Beginner11 min read

JavaScript has to be connected to your HTML before it can do anything. You do that with the <script> element, either by writing code inside it or by pointing it at a separate .js file.

Where you place the script, and a small attribute called defer, make a big difference. A script in the wrong place can slow the page down or fail because the elements it needs haven't loaded yet. This lesson shows the reliable setup used on professional sites, so you can avoid that whole category of bugs.

Writing JavaScript inside a script tag

HTML
<script>
  console.log("Hi from inside the HTML");
</script>

Inline scripts are fine for small experiments and for the examples on this site. On a real website, though, they mix code into the HTML and can't be reused by other pages.

defer, async and script placement

The browser reads HTML from top to bottom. A plain <script> in the <head> stops everything until it has downloaded and run, and it can't find elements that haven't been read yet.

OptionBehaviour
<script src> at the end of <body>Runs after the HTML above it. The traditional fix.
<script src defer> in <head>Downloads alongside the HTML and runs after the page is read, in order. Recommended.
<script src async>Downloads alongside the HTML and runs as soon as it's ready, in any order. Suits independent scripts like analytics.
<script type="module" src>Deferred automatically, and lets you use import and export. See Modules.

A common error: "Cannot read properties of null"

If a script runs before the HTML it needs, document.querySelector() returns null, and the next line fails with an error such as Cannot read properties of null. When you see that message, check two things: that the selector is spelled correctly, and that the script has defer or sits at the end of the body. Most of the time, one of those is the cause.

JavaScript Script Tag Syntax

Script tags

<script> /* inline code */ </script>
<script src="js/app.js" defer></script>
<script type="module" src="js/main.js"></script>

JavaScript Script Tag Summary

  • JavaScript is added to a page with the <script> element.
  • External .js files are best for real sites because they're reusable and cached.
  • A script with src must have nothing between its tags.
  • defer runs the script after the HTML is read, in order; async runs it as soon as it loads.
  • A null error often means the script ran before the HTML it needs.

JavaScript Script Tag Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

Too early!

The first script runs before the heading exists, so it finds nothing. The second runs after.

<script>
  console.log("Before:", document.querySelector("h1"));
</script>

<h1>Welcome</h1>

<script>
  console.log("After:", document.querySelector("h1"));
</script>
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 1 to 3When this runs, the browser hasn't read the <h1> yet, so the result is null.
  2. Lines 7 to 9By now the heading exists, so we get the element.
Example 2

A typical page setup

This is what a real page looks like. (The editor runs both files together, just like the browser would.)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Weather</title>
  <script src="data:text/javascript,console.log('app.js loaded (deferred)')" defer></script>
</head>
<body>
  <h1>Today: Sunny ☀️</h1>
  <script>
    console.log("Inline script at the end of body");
  </script>
</body>
</html>
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 6In a real project this would be src="app.js". defer means "download now, run when the HTML is ready".
  2. Lines 10 to 12An inline script at the end of the body runs first, because deferred scripts wait until parsing is finished.

Common JavaScript Script Tag Mistakes

Code inside a script with src

Don't
<script src="app.js">
  console.log("This never runs");
</script>
Do
<script src="app.js"></script>
<script>
  console.log("Separate script");
</script>

When src is set, the content between the tags is ignored.

Script tags inside a .js file

Don't
<script>
  console.log("Hello");
</script>
Do
console.log("Hello");

A .js file is pure JavaScript. HTML tags in it cause a syntax error on the first line.

JavaScript Script Tag in Real Projects

How real projects load JS

Most modern sites load one or a few bundled files with defer or type="module", created by tools like Vite or webpack. Third-party scripts like analytics and chat widgets usually use async so they never slow the page down.

JavaScript Script Tag Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Load app.js so it runs after the HTML is parsed.

<script ="app.js" ></script>
Multiple choicemedium

What will a plain script in the <head> get from document.querySelector("button") when the button is in the body?

Multiple choicemedium

Which attribute makes scripts run in order after parsing?

Fix the bugmedium

The script runs before the paragraph exists, so it fails. Move the script so it can find the paragraph (don't change the JavaScript itself).

<script>
  document.querySelector("#greet").textContent = "Hello from JS!";
</script>
<p id="greet">Waiting…</p>
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • The paragraph was updated
  • No errors

JavaScript Script Tag Quiz

3 questions to check what you learned.

  1. What file extension do JavaScript files use?

    • .js
    • .java
    • .jsx only
    • .script
  2. What's the difference between async and defer?

    • There is none
    • defer runs in order after parsing; async runs as soon as it downloads, in any order
    • async is faster in all cases
    • defer only works on inline scripts
  3. Can a <script src="x.js"> also contain code between its tags?

    • No, the inline code is ignored
    • Yes, both run
    • Only comments
    • Only if type="module"

JavaScript Script Tag Challenge

Count the paragraphs

Write a script after the HTML that logs exactly Paragraphs: 3 by counting the <p> elements with document.querySelectorAll("p").length.

// your code here
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Logs "Paragraphs: 3"