Adding jQuery to a Page
Before you can use $, the browser must download and run the jQuery file. There are three common ways to add it: a <script> tag pointing at a CDN, a copy on your own server, or a package installed with npm and bundled with your code.
In this lesson you will add jQuery 4.0 in each way, check which version loaded, pick between the full and slim builds, and fix the classic "$ is not defined" and "$ clashes with another library" problems.
Option 1: a CDN script tag
A CDN (Content Delivery Network) serves popular files from servers close to the visitor. The official jQuery CDN is code.jquery.com, and many sites use jsDelivr, which mirrors npm packages. Put the tag just before your own scripts:
<script src="https://code.jquery.com/jquery-4.0.0.min.js"
integrity="sha256-OaVG6prZf4v69dPg6PhVattBXkcOWQB62pdZ3ORyrao="
crossorigin="anonymous"></script>
<script src="js/app.js"></script>The integrity attribute is Subresource Integrity (SRI): a fingerprint (hash) of the exact file. If the CDN ever served a changed or hacked file, the hash would not match and the browser would refuse to run it. crossorigin="anonymous" is needed for the check to work across sites. Copy both values from releases.jquery.com, never type a hash by hand.
The examples in this course load jQuery from jsDelivr. This page prints which version loaded:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Which jQuery?</title>
</head>
<body>
<h1>Library check</h1>
<p id="status">Checking...</p>
<script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
<script>
if (window.jQuery) {
$("#status").text("jQuery " + $.fn.jquery + " is ready.");
} else {
document.querySelector("#status").textContent = "jQuery did not load.";
}
</script>
</body>
</html>$.fn.jquery holds the version string, here 4.0.0. Checking window.jQuery first is useful when a CDN might be blocked, for example on an office network.
Option 2: host the file yourself
Download jquery-4.0.0.min.js from the official download page, save it in your project (for example js/vendor/), and link to it with a relative path:
<script src="js/vendor/jquery-4.0.0.min.js"></script>
<script src="js/app.js"></script>Self-hosting avoids depending on another company's servers and works offline during development. Keep the version number in the file name so you always know what you are running.
You will see two kinds of file: jquery-4.0.0.js is the readable, uncompressed version, useful while debugging; jquery-4.0.0.min.js is minified (spaces and long names removed) and is the one to use on a live site.
Full build or slim build?
jQuery comes in two builds:
| Build | File | Includes | Size (gzipped, approx.) |
|---|---|---|---|
| Full | jquery-4.0.0.min.js | Everything | 27 KB |
| Slim | jquery-4.0.0.slim.min.js | No AJAX, no effects (.animate(), .fadeIn()...), no Deferred or Callbacks | 19 KB |
Use the slim build if your page only selects elements, handles events and changes classes, and uses fetch() and CSS for the rest. If a plugin calls $.ajax() or .fadeIn(), it needs the full build.
Script order and defer
Order matters. jQuery must run before any script that uses $, and plugins must load after jQuery but before your code:
<head>
<script src="js/vendor/jquery-4.0.0.min.js" defer></script>
<script src="js/vendor/datepicker-plugin.js" defer></script>
<script src="js/app.js" defer></script>
</head>The defer attribute downloads scripts without blocking the page and runs them, in order, after the HTML has been parsed. So you can keep scripts in <head> and still have every element available. The next lesson, Document Ready & DOMContentLoaded, explains why that matters.
Option 3: npm and a bundler
In projects built with a tool such as Vite (see npm, Packages & Build Tools), install jQuery as a package and import it like any other module:
npm install jquery@4.0.0// main.js
import $ from "jquery"; // default import
// import { $ } from "jquery"; // a named import also works in jQuery 4
$("#status").text(`Running jQuery ${$.fn.jquery}`);jQuery 4 ships a real ES module build, so bundlers pick the right file automatically. One difference: the module version does not create a global window.$. Code inside your modules uses the imported $; an old plugin that expects a global jQuery will need it attached to window first, or a version of the plugin that supports imports.
When $ belongs to someone else: noConflict
$ is a popular name, and some older libraries also use it. jQuery.noConflict() gives $ back to whichever library owned it before jQuery loaded. You then use the full name jQuery or your own alias:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>noConflict</title>
</head>
<body>
<p id="a">Waiting...</p>
<p id="b">Waiting...</p>
<script>
// Pretend another library already uses $
window.$ = function () { return "the other library"; };
</script>
<script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
<script>
const jq = jQuery.noConflict(); // $ goes back to the other library
jq("#a").text("jq() is jQuery " + jq.fn.jquery);
jQuery("#b").text("$() now returns: " + $());
</script>
</body>
</html>WordPress loads its bundled jQuery in this no-conflict mode, so $ is not defined there by default. The usual fix is to receive $ as a parameter inside a ready handler:
jQuery(function ($) {
// inside this function, $ is jQuery again
$(".menu-toggle").on("click", () => $(".site-nav").toggleClass("open"));
});The plain JavaScript way
Plain JavaScript needs no installation at all. The modern equivalent of "load the library, then my code" is simply your own script, often as a module:
<script type="module" src="js/app.js"></script>Module scripts are deferred automatically, run in strict mode and can import other files. You will compare jQuery and module code throughout the course.
Common mistakes
- Wrong order. Your script, or a plugin, appears above the jQuery tag. Always load jQuery first.
- Mixing
deferand inline scripts. Inline code runs before deferred jQuery exists. - Loading jQuery twice. A theme loads one version and a plugin loads another; the second copy replaces the first and wipes plugins attached to it. Load it once.
- Using the slim build with AJAX code.
$.ajaxisundefinedin slim, so calls throw "$.ajaxis not a function". - Typing an SRI hash wrongly. One wrong character and the browser blocks the file. Copy it from the official release page.
Key points
- Add jQuery with a CDN
<script>tag (ideally with SRI), a self-hosted copy, ornpm install jqueryplusimport $ from "jquery". - jQuery must load before plugins, and plugins before your own code;
deferkeeps that order. - The slim build drops AJAX, effects, Deferred and Callbacks to save about 8 KB gzipped.
$.fn.jquerytells you which version is running.jQuery.noConflict()releases$; in WordPress usejQuery(function ($) { ... }).
Exercise
Write a complete page that loads jQuery 4.0.0 from jsDelivr, then shows the version number inside a <span id="ver"> and the length of the page title inside <span id="len">. Use $.fn.jquery and document.title.length. Then write the plain JavaScript lines that would fill the same two spans without jQuery.
Show solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Version check for Isha</title>
</head>
<body>
<p>jQuery version: <span id="ver"></span></p>
<p>Title length: <span id="len"></span></p>
<script src="https://cdn.jsdelivr.net/npm/jquery@4.0.0/dist/jquery.min.js"></script>
<script>
$("#ver").text($.fn.jquery);
$("#len").text(document.title.length);
// Plain JavaScript equivalent:
// document.querySelector("#ver").textContent = "(no jQuery)";
// document.querySelector("#len").textContent = document.title.length;
</script>
</body>
</html>.text() accepts numbers as well as strings, just like textContent, which converts the number to text.
Quick Quiz
1. What does the integrity attribute on a CDN script tag do?
Subresource Integrity compares the downloaded file with a known hash and blocks it if they differ.
2. Which feature is missing from the slim build of jQuery 4?
The slim build excludes the AJAX and effects modules, plus Deferred and Callbacks.
3. Why does an inline script that uses $ fail when jQuery is loaded with defer?
Only external scripts can be deferred; inline code runs as soon as the parser reaches it.
4. In WordPress, $ is undefined but jQuery works. What is the usual fix?
WordPress uses no-conflict mode; the ready handler receives jQuery as its first argument, which you can name $.
Learn jQuery with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
