JavaScript $ Is Not A Function | Fix jQuery Errors Fast

JavaScript “$ is not a function” means $ isn’t a callable jQuery function on that page—load jQuery correctly and avoid $ conflicts.

You click a button, your page freezes, and the console throws the same line again. This error shows up often in old sites, new builds, WordPress themes, Shopify snippets, and single-page apps. The good news is that the message is literal. Your code tried to run $() like a function, and at that moment $ was something else.

This article helps you spot what $ is right now, why it changed, and what to fix in a repeatable way. You’ll also get copy-ready checks for common setups: script tags, bundlers, WordPress, and “noConflict” pages.

What The Error Means In Plain Terms

In JavaScript, a “function” is a value you can call with parentheses, like fn(). When you see “$ is not a function,” the browser is saying that the current value stored in the variable named $ can’t be called.

Most of the time, people expect $ to be jQuery’s function. jQuery sets both window.jQuery and window.$. If jQuery didn’t load, loaded too late, or got replaced, then $ won’t be the thing you expect.

Quick check — open DevTools, go to the Console, and type typeof $. If you get "function", jQuery is present and callable. If you get "undefined", jQuery isn’t on the page at all. If you get "object" or "string", something overwrote it.

Fast Diagnosis Steps You Can Do In Two Minutes

Before changing code, pin down the root cause. A small check now saves you from random edits later.

  1. Reproduce the error — Trigger the click, load, or timer that throws it, then note the first file and line number in the stack trace.
  2. Check jQuery presence — Run window.jQuery and window.jQuery && typeof window.jQuery to see if it exists and what type it is.
  3. Inspect the $ value — Run $ and typeof $. If it prints something like a DOM element or a library object, you’ve found the collision.
  4. Verify script order — In the Elements panel, find your script tags and confirm jQuery loads before the script that calls $().
  5. Look for duplicate loads — In the Network tab, filter by “jquery” and check if you load it more than once, from different versions.

When you have those answers, the fix almost always falls into one of the patterns below.

Common Causes And Fixes That Work

What You See Likely Cause Fix To Try
$ is undefined jQuery not loaded Load jQuery before your code
$ is an object Another library took $ Use jQuery or noConflict
Error only on some pages Scripts conditionally enqueued Load dependencies on every page that needs them
Works after refresh, fails on first load Code runs before DOM or before scripts finish Wrap in DOM-ready or defer correctly
Fails after a plugin update Version mismatch or duplicate jQuery Remove extra copies; keep one source

Load jQuery before the code that uses $

If you use plain script tags, order is the first thing to fix. jQuery must load first, then your plugin, then your custom script. If you use defer or async, be careful: async can reorder loads, and that can break pages.

  • Move jQuery earlier — Place the jQuery script tag above your script that calls $().
  • Avoid async on jQuery — Keep jQuery as a normal script or use defer on all related scripts so order stays consistent.
  • Confirm the URL loads — Open the jQuery URL in a new tab and check for 404s, blocked requests, or CSP errors.

Also check caching — If you use a cache plugin or CDN, an old HTML version can point at a removed file. Purge cache, hard-reload, then recheck Network for the right jQuery file. If your site uses a Content Security Policy, confirm the jQuery host is allowed, or the browser will block it silently. In the Console, CSP blocks show as red errors with “Refused to load script”. Fix the policy, then reload. Test in incognito once too.

Stop $ collisions with noConflict or by using jQuery

Many libraries like Prototype, MooTools, Zepto, and some theme scripts can use $ too. If that library loads after jQuery, it can replace window.$. jQuery still exists as window.jQuery, so the simplest fix is to call jQuery() instead of $().

  1. Swap $ for jQuery — Change $(selector) to jQuery(selector) in your code.
  2. Wrap your code — Use (function($){ ... })(jQuery); so $ is locally mapped to jQuery inside that block.
  3. Use noConflict — Call jQuery.noConflict() only when you truly need $ for another library.

Make sure your code runs after the page is ready

If jQuery is present but your selectors return empty or your handlers don’t bind, your code may be running too early. A script placed in the head without defer can run before the target elements exist.

  • Use DOM-ready — Wrap setup code in jQuery(function($){ ... }) so it waits for the DOM.
  • Prefer defer — Add defer to scripts when you can, and keep all related scripts consistent.
  • Bind after templates render — If your HTML is injected later, bind events with delegation using on() on a stable parent.

Fixing JavaScript $ Is Not A Function In WordPress

WordPress often triggers this error in themes and plugins because it runs jQuery in noConflict mode by default. That means $ may not point to jQuery in the global scope. On top of that, scripts can be enqueued in the wrong order, or loaded only on certain templates.

Use the WordPress-safe wrapper

In WordPress, the safest pattern is to wrap your code and pass jQuery in as $ inside the wrapper. This keeps your code tidy and avoids global collisions.

  1. Wrap in an IIFE — Put your code inside (function($){ ... })(jQuery);.
  2. Keep $ inside the wrapper — Don’t call $ outside that function on WordPress pages.
  3. Test in the Customizer — Some themes load scripts differently in preview mode, so test both front end and Customizer.

Enqueue jQuery and set dependencies

If you enqueue scripts, set jQuery as a dependency so WordPress loads it first. If you print scripts manually in a theme file, you can end up with duplicates or wrong order.

  • Declare dependencies — In wp_enqueue_script, include array('jquery') so WordPress handles order.
  • Avoid extra CDNs — Don’t load a second jQuery from a CDN unless you’ve planned for it and removed the core one.
  • Check template conditions — If a script is only enqueued on one page type, confirm you aren’t using it on other pages too.

Fixing The Error In Bundlers And Modern Builds

Build tools change how scripts load. In a module world, jQuery may not be global, even when it is installed. Your code can run in strict scope where $ isn’t defined unless you import it.

Import jQuery where you use it

If you use Webpack, Vite, Parcel, or Rollup, treat jQuery like any other dependency. Import it in the file that needs it, or provide it explicitly if you have older plugins that expect a global.

  1. Install jQuery — Add it with your package manager so it’s in your lockfile and build.
  2. Import in modules — Use import $ from 'jquery'; (or import jQuery from 'jquery';) and call it directly.
  3. Expose globals for legacy code — If a plugin expects window.$, assign window.$ = $ and window.jQuery = $ at your entry.

Watch for duplicate copies in bundles

A subtle version split can happen when one dependency brings its own jQuery copy. Then plugins attach to one copy, while your code uses another. You’ll see odd behavior like $.fn missing a plugin method.

  • Search your build output — Look for “jquery” in the final bundle and check how many times it appears.
  • Deduplicate packages — Use your package manager’s dedupe tools and align versions across dependencies.
  • Verify plugin attachment — In the console, check typeof $.fn.pluginName right after the plugin loads.

Preventing “$ Is Not A Function” From Coming Back

Once you fix the immediate issue, set a few guardrails so the same mistake doesn’t return after a theme change or plugin update. This is less about adding extra code and more about making dependencies obvious.

  • Prefer one source of jQuery — Pick core, a CDN, or your bundle, then stick to it across the site.
  • Keep script order predictable — Avoid mixing async scripts with order-dependent code.
  • Lint for globals — Add lint rules that warn when you use $ without importing or without a wrapper.
  • Log a clear check — In dev, add a small assertion like if (typeof jQuery !== 'function') console.warn('jQuery missing');.
  • Retest after updates — After changing themes, plugins, or build output, run through the same two-minute diagnosis again.

If you still see the message after these fixes, go back to the console and print $ and window.jQuery again. The value you see will tell you what’s taking over. Once you know that, the path to a fix stays straightforward.

As a final sanity check, search your codebase for “$ =” and “window.$” assignments. A stray assignment can replace jQuery without you noticing. When you remove that line or localize $ inside a wrapper, the page usually settles down and your handlers start firing again.

On pages where you can’t change the load order, switch your calls from $(...) to jQuery(...). It’s a small change, and it sidesteps many collisions. That single swap also helps on WordPress pages where the global $ is intentionally reserved.

When you see javascript $ is not a function in logs from a client site, treat it like a signal, not a mystery. It points to a missing dependency, a timing issue, or a name collision. Fix that one cause, then lock it in with consistent loading rules.

It’s also normal to see the same root causes in different places. A landing page with custom code may load scripts differently from a blog post template. A checkout page may have extra scripts from payment widgets. Run the same checks per page type until the console stays quiet.

After you’ve confirmed the fix, keep an eye on your monitoring or error reporting. If the same error returns, you’ll often spot which release introduced a second jQuery file or changed a script tag attribute. Roll back that change or align the dependency list, and the issue ends.

One more time, here’s the core takeaway in plain words: javascript $ is not a function happens when $ isn’t jQuery at the moment you call it. Make jQuery load once, load it first, and keep $ from being overwritten.