The .off() method removes event handlers attached with .on(). This tutorial covers all official signatures, five worked examples from the jQuery API, delegated unbinding with the ** selector, namespace cleanup, comparison with legacy .die(), and best practices for plugin authors.
01
Syntax
.off(type, sel, fn)
02
Pair
Undoes .on()
03
Delegate
Match selector
04
Namespaces
.off(".ns")
05
**
Delegated only
06
Since 1.7
Modern API
Fundamentals
Introduction
Binding events is only half the story. When widgets are destroyed, routes change in a single-page app, or AJAX replaces DOM sections, you must remove handlers to prevent memory leaks and duplicate callbacks. jQuery unified unbinding in version 1.7 with .off(), the counterpart to .on().
Before 1.7, developers juggled three methods: .unbind() for direct handlers, .undelegate() for delegated ones, and .die() for legacy .live() handlers. Today, .off() handles all cases with one flexible API — filter by event type, delegation selector, handler function, or namespace.
Concept
Understanding .off()
.off() does not remove elements from the DOM — it detaches JavaScript functions from jQuery’s internal event registry. When you call .off("click", "#btn", fn), jQuery finds the handler that matches all provided filters and removes it. Omit filters to remove broader sets of handlers.
For delegated events, the selector argument must exactly match what you passed to .on(). If you bound on body with .on("click", "#theone", flash), unbind with .off("click", "#theone", flash) on the same element.
💡
Beginner Tip
Think of .on() and .off() as opposites with identical argument patterns (except .on() also accepts eventData). Bind with .on("click.myApp", "li", fn); tear down with .off("click.myApp", "li", fn) or simply .off(".myApp").
Foundation
📝 Syntax
Four signatures from the official jQuery API (all since 1.7):
Click "Add Click" → #theone shows "Can Click!"
Click #theone → div flashes and fades
Click "Remove Click" → .off removes handler
#theone reverts to "Does nothing..."
How It Works
Delegation binds on body for clicks matching #theone. .off("click", "#theone", flash) requires the same element, event type, selector, and function reference used during binding.
Example 2 — Remove All Event Handlers
Calling .off() with no arguments clears every handler on matched elements.
Before: click and mouseenter handlers on each p
After $("p").off(): no handlers remain
Broadest cleanup — use during element teardown
How It Works
No filters means jQuery removes all direct and delegated handlers from each matched p. Use sparingly in shared code — prefer namespaces or specific handler references.
Example 3 — Remove All Delegated Click Handlers with "**"
Strip delegated clicks without removing direct click handlers on the same element.
#box has direct click + delegated click on p
.off("click", "**") on #box → delegated p clicks gone
Direct click on #box background still works
How It Works
The special selector "**" targets only handlers attached via delegation (with a child selector in .on()). Direct handlers bound with .on("click", fn) on the same element survive.
Example 4 — Remove One Handler by Function Reference
Official pattern: pass the same foo function given to .on().
jQuery
var foo = function() {
// Code to handle some kind of event
};
$( "body" ).on( "click", "p", foo );
$( "body" ).off( "click", "p", foo );
Two handlers on body → click p
.off("click", "p", handlerA) removes only handlerA
handlerB still runs — surgical removal
How It Works
Store handler functions in named variables so you can pass the identical reference to both .on() and .off(). Anonymous inline functions cannot be removed this way unless you keep a reference.
Example 5 — Remove Handlers by Namespace
Plugin-friendly cleanup: attach under .validator, remove all at once.
click.validator on button + keypress.validator on input
.off(".validator") removes BOTH
Other handlers without .validator namespace untouched
How It Works
Namespaces segment your handlers from other code’s handlers. Passing only ".validator" to .off() removes every handler attached with that namespace, regardless of event type.
Applications
🚀 Common Use Cases
Widget teardown — $("#widget").off(".myWidget") when removing a UI component.
Toggle binding — official bind/unbind button pattern from Example 1.
SPA route changes — $(document).off("click.myRoute", ".nav-link") before attaching new route handlers.
One-time handlers — $(this).off(event) inside the handler after first run.
Plugin isolation — namespace all bindings so .off() never removes foreign handlers.
Migrating from .die() — replace $("p").die("click") with $(document).off("click", "p").
🧠 How .off() Finds Handlers to Remove
1
Collect filters
jQuery reads your arguments: event type, namespace, delegation selector, handler function, or event object.
Parse
2
Scan registry
It searches the internal handler list on each matched element for entries that satisfy all filters.
Match
3
Detach matches
Matching handlers are removed from jQuery’s event data and will no longer fire.
Remove
4
🗑
Non-matches stay
Handlers that fail any filter remain active — enabling precise, scoped cleanup.
Important
📝 Notes
.off() was added in jQuery 1.7 as the unified replacement for .unbind(), .undelegate(), and (conceptually) .die().
Calling .off("click") removes both direct and delegated click handlers unless you use "**" for delegated-only removal.
Proxied handlers ($.proxy()) share one internal id — prefer namespaces when unbinding proxied functions.
Minimum requirement: provide either an event name or a namespace (e.g. ".myPlugin" alone is valid).
.off(event) removes the specific handler that is currently executing — useful for one-shot handlers.
Legacy: $(document).off("click") removes all document-level delegated clicks, including those that replaced .live().
Compatibility
Browser Support
.off() is a jQuery method available since jQuery 1.7 in all jQuery 1.x, 2.x, and 3.x releases. It works in every browser your jQuery version supports. Native equivalent: element.removeEventListener(type, fn) — but without jQuery's delegation, namespace, or multi-handler management.
✓ jQuery 1.7+
jQuery .off()
Supported in jQuery 1.7+ across all modern browsers and IE with supported jQuery builds. The current recommended way to remove handlers bound with .on(). Safe for all new jQuery projects.
100%Modern jQuery API
Google ChromeAll versions · Desktop & Mobile
Full support
Mozilla FirefoxAll versions · Desktop & Mobile
Full support
Apple SafariAll versions · macOS & iOS
Full support
Microsoft EdgeAll versions · Chromium & Legacy
Full support
Internet ExplorerIE 6+ · Legacy environments
Full support
OperaAll modern versions
Full support
.off()Universal
Bottom line: Use .off() in every jQuery 1.7+ project. Pair it with namespaced .on() bindings for safe plugin teardown. Never use removed .die() or deprecated .unbind() in new code.
Wrap Up
Conclusion
jQuery .off() completes the modern event API started by .on() in version 1.7. Whether you need to remove one delegated handler, clear an entire namespace, or tear down a widget completely, .off() provides the filters to do it precisely.
Bind with namespaces, store handler references when you need surgical removal, and use "**" when you only want to drop delegated handlers. Practice the official bind/unbind demo until .on() / .off() feel like two halves of one pattern.
Store handler refs when you need targeted .off(type, sel, fn)
Match delegation selectors exactly between .on() and .off()
Use .off(".myPlugin") for clean widget destruction
Prefer .off("click", "**") over bare .off("click") when keeping direct handlers
❌ Don’t
Call $("body").off() casually — it removes everything on body
Pass a different selector than you used in .on()
Rely on .off(fn) for proxied handlers bound to different contexts
Forget to unbind before re-binding the same event (causes duplicate handlers)
Use deprecated .unbind() or .die() in new jQuery 3 code
Summary
Key Takeaways
Knowledge Unlocked
Six things to remember about .off()
The modern way to unbind jQuery events.
6
Core concepts
📝01
Pair
Undoes .on().
API
🗑02
.off()
Remove all.
Broad
**03
Delegated
Only delegated.
Filter
.ns04
Namespace
.off(".ns")
Plugins
fn05
By ref
Same function.
Surgical
1.706
Modern
Use today.
Status
❓ Frequently Asked Questions
.off() removes event handlers that were attached with .on(). It is the modern unbinding API introduced in jQuery 1.7, replacing .unbind(), .undelegate(), and .die(). You can remove all handlers, filter by event type, delegation selector, handler function, or namespace.
.off() removes handlers bound with .on() — both direct and delegated. .die() only removed handlers attached with the removed .live() method. Migration: $('p').live('click', fn) became $(document).on('click', 'p', fn), and $('p').die('click') became $(document).off('click', 'p').
The special selector '**' removes all delegated click handlers from the element without removing direct click handlers bound on the element itself. Use it when you delegated with .on('click', 'li', fn) on a parent and want to clear only those delegated bindings.
Namespaces like .on('click.myPlugin', fn) let you remove only your plugin's handlers with .off('.myPlugin') without affecting other code. This is essential in large apps and plugins to avoid accidentally removing unrelated handlers.
Yes. If you bound with .on('click', '#theone', fn), you must pass the same '#theone' selector to .off(). A mismatched selector will not remove the handler.
All event handlers attached to the matched elements are removed — both direct and delegated. Use this carefully during widget teardown, or prefer scoped removal with event types, namespaces, or handler references.
Did you know?
When jQuery 1.7 shipped .on() and .off(), it retired three separate unbinding methods at once. A single call like $(document).off("click") can remove handlers that would have previously required knowing whether they were bound via .bind(), .delegate(), or .live() — which is why migrating legacy code to .on() / .off() simplifies maintenance dramatically.