A no-nonsense hands-on guide to jQuery 4.0.0 features. Learn how to test ES Modules, handle breaking changes, and why you might (or might not) upgrade.
Ten years. That's how long it took to get a major jQuery update. Most of us have moved on to React, Vue, or just plain Vanilla JS, but let's be honest—jQuery is still everywhere. I just spent the last four hours digging through the 4.0.0 release candidate to see if it's actually better or just another layer of technical debt.
Spoiler: It's a massive cleanup. If you're still supporting IE10, don't even bother reading. For the rest of us, here's how to actually test these features without breaking your sanity.
Browser Compatibility: jQuery 4.0 drops support for Internet Explorer entirely. You'll need modern browsers that support ES6+ features. Think Chrome 90+, Firefox 88+, Safari 14+, or Edge 90+.
Finally, jQuery isn't just a global object hanging off the window. It's now authored in ES modules. This means you can import it directly in modern browsers without needing a bundler that feels like it's about to overheat your laptop.
<script type="module"> import $ from 'https://code.jquery.com/jquery-4.0.0.module.js';
$(() => { console.log('jQuery version:', $.fn.jquery); // Should be 4.0.0 $('body').css('background', '#f4f4f4'); });</script>The 2 AM Reality: It feels weirdly modern. Not having to worry about the order of <script> tags is a relief, but remember: if you're using old plugins that expect window.jQuery to exist globally, they will crash. You'll have to manually expose it or refactor those ancient scripts.
Here's how to bridge the gap:
// Option 1: Expose jQuery globally for legacy pluginsimport $ from 'https://code.jquery.com/jquery-4.0.0.module.js';window.jQuery = window.$ = $;
// Now your old plugins will workimport 'legacy-plugin.js'; // Expects window.jQuery// Option 2: Refactor to ES modules (recommended)import $ from 'https://code.jquery.com/jquery-4.0.0.module.js';import { legacyPlugin } from './legacy-plugin-modernized.js';
$(() => { legacyPlugin.init();});The team finally grew a backbone and deleted functions that have been deprecated since the dawn of time. If your code uses these, it's going to scream at you.
These utility functions have been removed in jQuery 4.0. You'll need to replace them with native JavaScript equivalents:
$.isArray() → Array.isArray()$.isFunction() → typeof x === 'function'$.isNumeric() → !isNaN(parseFloat(x)) && isFinite(x)$.trim() → String.prototype.trim()$.type() → typeof or Object.prototype.toString.call()$.isWindow() → x != null && x === x.window$.isPlainObject() → Use a library like Lodash or write your own checkThe "What Just Happened?" Test: Try running any of these in the console with jQuery 4.0.
// ❌ This will throw a TypeError in 4.0try { const isArr = $.isArray([1, 2, 3]); const trimmed = $.trim(' hello '); const isNum = $.isNumeric('123');} catch (e) { console.warn('These functions no longer exist!');}
// ✅ Use native alternatives insteadconst isArr = Array.isArray([1, 2, 3]);const trimmed = ' hello '.trim();const isNum = !isNaN(parseFloat('123')) && isFinite('123');// Before (jQuery 3.x)function validateForm(data) { if ($.isArray(data.items)) { const clean = $.trim(data.name); if ($.isNumeric(data.age)) { return true; } } return false;}
// After (jQuery 4.0)function validateForm(data) { if (Array.isArray(data.items)) { const clean = data.name.trim(); if (!isNaN(parseFloat(data.age)) && isFinite(data.age)) { return true; } } return false;}Real-world take: Look, if you're still using $.trim() in 2026, we need to have a talk. Native String.prototype.trim() has been supported since forever. This cleanup is long overdue, but it means you can't just "drop-in" 4.0 and expect it to work without a search-and-replace session.
Pro Tip: Use your IDE's "Find and Replace" with regex to quickly migrate:
- Find:\$.isArray(→ Replace:Array.isArray(
- Find:\$.trim(→ Replace:.trim(
- Find:\$.isNumeric(→ Replace with your numeric check function
Before upgrading to jQuery 4.0, run through this checklist:
$.isArray, $.trim, $.isNumeric, etc.)This is the "boring but important" part. If you've ever fought with a strict Content Security Policy (CSP), you know the pain of XSS errors. jQuery 4.0 now supports Trusted Types, which helps you work with strict CSP without violating security policies.
When you have a strict CSP, operations like $('#container').html(userContent) can trigger violations because the browser can't verify the content is safe. Trusted Types API allows you to create a policy that sanitizes content before it's used.
// If your policy requires Trusted Types, jQuery 4.0 plays niceconst policy = window.trustedTypes.createPolicy('myPolicy', { createHTML: (string) => { // Sanitize the HTML - remove script tags, etc. return string.replace( /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '' ); },});
const safe = policy.createHTML('<b>Verified Content</b>');$('#container').html(safe); // No CSP violation here.// ❌ This would trigger CSP violation in strict mode$('#container').html(userGeneratedContent);
// ✅ With jQuery 4.0 and Trusted Typesconst safeContent = trustedTypesPolicy.createHTML(userGeneratedContent);$('#container').html(safeContent);You'll need Trusted Types support if:
The 2 AM Reality: You probably won't care about this until your security auditor starts breathing down your neck. But when they do, you'll be glad you're on 4.0.
This one is subtle and potentially annoying. jQuery now follows the W3C spec for focus event order: blur → focusout → focus → focusin. Previously, jQuery had its own order that didn't match the spec, which could break form validation logic.
If your form validation relies on the specific order of focus events, this change will break your logic. The old jQuery order was different from the W3C standard, and now jQuery 4.0 aligns with the spec.
$('#myInput').on('blur focusout focus focusin', (e) => { console.log(`Fired: ${e.type} at ${new Date().getTime()}`);});
// Click away from input, then click back in// You'll see the new order in console// ❌ Old code that might breaklet validationState = 'idle';
$('#email').on('focus', () => { validationState = 'checking'; // This might fire in wrong order now});
$('#email').on('blur', () => { if (validationState === 'checking') { // This logic might not work as expected validateEmail(); }});
// ✅ Better approach - use specific events$('#email').on('focusin', () => { // User is focusing in showValidationHint();});
$('#email').on('focusout', () => { // User is leaving the field validateEmail();});focusin/focusout for better cross-browser supportCheck your logs. If your form validation relied on the old "jQuery-only" order, your logic is now officially broken. Fix it.
Here are the most common issues you'll encounter when upgrading:
Problem: Old plugins expect window.jQuery to exist.
Solution: Either expose jQuery globally or update plugins to use ES modules.
// Quick fiximport $ from 'jquery';window.jQuery = window.$ = $;Problem: Libraries that bundle their own jQuery might conflict.
Solution: Check if libraries have been updated for jQuery 4.0, or use a single jQuery instance.
Problem: Older bundlers might not handle ES modules correctly.
Solution: Update to modern bundlers (Webpack 5+, Vite, Rollup) that support ES modules natively.
Problem: Focus event order changes break validation timing.
Solution: Refactor to use focusin/focusout explicitly instead of relying on event order.
Problem: You forgot to replace all $.trim() calls.
Solution: Use a linter or automated tool to find and replace all instances before upgrading.
$.isArray calls. jQuery 3.7.x is still maintained and secure.Related Article: For a comprehensive overview of what changed and why it matters, read jQuery 4.0: What Actually Changed (And Why It Matters).
Migrated to jQuery 4.0? Hit a wall? Found a workaround? Share your migration story in the comments below. Your pain (and solutions) might save someone else's weekend.
No comments yet
Loading comments...