and include file extensions in import paths in many setups. If nothing happens, check DevTools Console for errors and Network for 404s. If you see Uncaught TypeError about null elements, move the script to the end of or add defer. If module scripts fail due to file:// restrictions or CORS, serve the files with a local server instead of opening the HTML directly.","url":"https://mimo.org/tutorials/javascript/how-to-link-javascript-to-html","isPartOf":{"@type":"CreativeWork","name":"Mimo Tutorials","url":"https://mimo.org/tutorials","@id":"https://mimo.org/tutorials#tutorials"},"mainEntityOfPage":"https://mimo.org/tutorials/javascript/how-to-link-javascript-to-html","publisher":{"url":"https://mimo.org","@type":"Organization","name":"Mimo"},"@context":"https://schema.org","headline":"How to Link JavaScript to HTML","@type":"TechArticle"}

How to Link JavaScript to HTML

What you’ll build or solve

You’ll connect an HTML page to JavaScript so clicks, inputs, and other page events can run your code.

When this approach works best

Linking JavaScript to HTML works best when you want to:

  • Keep JavaScript in its own file so it stays readable and reusable across pages.
  • Add interactivity, such as handling button clicks or form validation.
  • Work on a multi-file project where HTML and JavaScript change independently.

This is a bad idea when you paste large blocks of JavaScript directly into HTML for a real project. Inline scripts get messy fast and are harder to debug.

Prerequisites

  • A basic HTML file you can open in a browser
  • A text editor such as VS Code
  • No extra tools required

Step-by-step instructions

1) Link an external .js file with a <script> tag

This is the most common approach. Create a JavaScript file and link it from your HTML.

Option A: Script at the end of <body> (most common)

Project structure:

index.html
app.js
<!-- index.html -->
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>JS Demo</title>
</head>
<body>
  <h1 id="title">Hello</h1>

  <script src="app.js"></script>
</body>
</html>
// app.js
const title = document.querySelector("#title");
title.textContent = "Hello from JavaScript";

What to look for: placing the <script> tag right before </body> helps avoid DOM timing issues.


Option B: Script in <head> with defer

Use this when you want scripts in <head> but still need safe DOM access.

<head>
  <meta charset="utf-8" />
  <script src="app.js" defer></script>
  <title>JS Demo</title>
</head>

What to look for: without defer, code that reads the DOM can run before elements exist.


Option C: Script in a subfolder

Project structure:

index.html
js/app.js
<script src="js/app.js"></script>

Option D: Script one folder up

Project structure:

pages/index.html
app.js
<script src="../app.js"></script>

2) Use an inline script for small, page-only code

Inline scripts work for quick demos or tiny behaviors.

<button id="buy">Buy</button>

<script>
  const button = document.querySelector("#buy");
  button.addEventListener("click", () => {
    alert("Thanks!");
  });
</script>

What to look for: if you place the script above the button, button will be null. Put inline scripts near the bottom of the page.


Examples you can copy

Example 1: Minimal external script link

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Page</title>
</head>
<body>
  <p id="note">Waiting...</p>
  <script src="app.js"></script>
</body>
</html>
// app.js
const note = document.querySelector("#note");
note.textContent = "Loaded!";

Example 2: Two scripts (vendor plus app)

<script src="vendor.js"></script>
<script src="app.js"></script>

What to look for: order matters. If app.js depends on something in vendor.js, load vendor.js first.


Example 3: Use type="module" for modern imports

<script type="module" src="app.js"></script>
// app.js
import { formatPrice } from "./utils.js";

const price = formatPrice(9.99);
console.log(price);

What to look for: with modules, include file extensions in imports in most setups, such as ./utils.js.


Example 4: Link a script from a CDN

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="app.js"></script>

What to look for: you need an internet connection for CDN scripts to load.


Common mistakes and how to fix them

Mistake 1: Wrong file path in src

What you might do:

<script src="/app.js"></script>

Why it breaks:

A leading / points to the site root. When you open an HTML file locally, that usually does not map to your project folder.

Correct approach:

Use a relative path.

<script src="app.js"></script>

Mistake 2: Script runs before the elements exist

What you might do:

<head>
  <script src="app.js"></script>
</head>
<body>
  <button id="buy">Buy</button>
</body>

Why it breaks:

The script runs before the button exists, so querySelector("#buy") returns null.

Correct approach:

Use defer:

<script src="app.js" defer></script>

Or place the script at the end of <body>.


Troubleshooting

If nothing happens:

  • Open DevTools and check the Console for errors. A missing file or syntax error often shows up there.

If your script file returns 404:

  • Open the Network tab, refresh, and look for your .js file. Fix the src path.

If you see Uncaught TypeError: Cannot read properties of null:

  • Your script is running before the element exists. Use defer or move the script tag to the end of <body>.

If modules fail with a CORS or file error:

  • Serve your files with a local server instead of opening index.html directly. Many browsers restrict ES modules from file://.

If a script works sometimes but not always:

  • Check script order and remove duplicate script tags that load the same file twice.

Quick recap

  • Use <script src="app.js"></script> near </body> for the simplest setup.
  • Use <script src="app.js" defer></script> when loading from <head>.
  • Use an inline script only for small, page-only code.
  • If the script does not run, check the Console and verify the src path.