Gathering detailed insights and metrics for bind-event-listener
Gathering detailed insights and metrics for bind-event-listener
Gathering detailed insights and metrics for bind-event-listener
Gathering detailed insights and metrics for bind-event-listener
react-event-listener
A React mixin that enable components to bind events
discord.js-message-listener
A simple utility to bind events on discord message.
@indevstudio/react-event-listener
A React component that allow to bind events on the global scope
@tomvillp/bind-event
DOM Events binding utility, which returns a function to automatically remove event listener.
A utility to make binding and (especially) unbinding DOM events easier
npm install bind-event-listener
Typescript
Module System
Node Version
NPM Version
99.7
Supply Chain
99.5
Quality
75.8
Maintenance
100
Vulnerability
100
License
TypeScript (98.87%)
JavaScript (1.13%)
Total Downloads
19,667,878
Last Day
13,107
Last Week
365,069
Last Month
1,566,131
Last Year
12,355,862
MIT License
153 Stars
107 Commits
8 Forks
4 Watchers
11 Branches
4 Contributors
Updated on Jun 17, 2025
Minified
Minified + Gzipped
Latest Version
3.0.0
Package Id
bind-event-listener@3.0.0
Unpacked Size
20.32 kB
Size
6.38 kB
File Count
15
NPM Version
8.19.3
Node Version
18.13.0
Published on
Apr 26, 2023
Cumulative downloads
Total Downloads
A well typed utility to make creating and removing DOM event listeners safer and more ergonomic.
1import { bind, UnbindFn } from 'bind-event-listener'; 2 3const unbind: UnbindFn = bind(button, { 4 type: 'click', 5 listener: function onClick(event) {}, 6}); 7 8// when you are all done: 9unbind();
1import { bindAll } from 'bind-event-listener'; 2 3const unbind = bindAll(button, [ 4 { 5 type: 'click', 6 listener: function onClick(event) {}, 7 options: { capture: true }, 8 }, 9 { 10 type: 'mouseover', 11 listener: function onMouseOver(event) {}, 12 }, 13]); 14 15// when you are all done: 16unbind();
When using addEventListener()
, correctly unbinding events with removeEventListener()
can be tricky.
removeEventListener
(it can be easy to forget!)1target.addEventListener('click', onClick, options); 2 3target.removeEventListener('click', onClick, options);
removeEventListener
1target.addEventListener( 2 'click', 3 function onClick() { 4 console.log('clicked'); 5 }, 6 options, 7); 8 9// Even those the functions look the same, they don't have the same reference. 10// The original onClick is not unbound! 11target.removeEventListener( 12 'click', 13 function onClick() { 14 console.log('clicked'); 15 }, 16 options, 17);
1// Inline arrow functions can never be unbound because you have lost the reference! 2target.addEventListener('click', () => console.log('i will never unbind'), options); 3target.removeEventListener('click', () => console.log('i will never unbind'), options);
capture
value option1// add a listener: AddEventListenerOptions format 2target.addEventListener('click', onClick, { capture: true }); 3 4// not unbound: no capture value 5target.removeEventListener('click', onClick); 6 7// not unbound: different capture value 8target.removeEventListener('click', onClick, { capture: false }); 9 10// successfully unbound: same capture value 11target.removeEventListener('click', onClick, { capture: true }); 12// this would also unbind (different notation) 13target.removeEventListener('click', onClick, true /* shorthand for { capture: true } */);
1// add a listener: boolean capture format
2target.addEventListener('click', onClick, true /* shorthand for { capture: true } */);
3
4// not unbound: no capture value
5target.addEventListener('click', onClick);
6// not unbound: different capture value
7target.addEventListener('click', onClick, false);
8
9// successfully unbound: same capture value
10target.addEventListener('click', onClick, true);
11// this would also unbind (different notation)
12target.addEventListener('click', onClick, { capture: true });
bind-event-listener
solves these problems
bindAll
) you get back a simple unbind
functionremoveEventListener
capture
value is used with addEventListener
is used with removeEventListener
You will find an even fuller rationale for this project in my course: "The Ultimate Guide for Understanding DOM Events"
bind
: basic1import { bind, UnbindFn } from 'bind-event-listener'; 2 3const unbind: UnbindFn = bind(button, { 4 type: 'click', 5 listener: onClick, 6}); 7 8// when your are all done: 9unbind();
bind
: with options1import { bind } from 'bind-event-listener'; 2 3const unbind = bind(button, { 4 type: 'click', 5 listener: onClick, 6 options: { capture: true, passive: false }, 7}); 8 9// when you are all done: 10unbind();
bindAll
: basic1import { bindAll } from 'bind-event-listener'; 2 3const unbind = bindAll(button, [ 4 { 5 type: 'click', 6 listener: onClick, 7 }, 8]); 9 10// when you are all done: 11unbind();
bindAll
: with options1import { bindAll } from 'bind-event-listener';
2
3const unbind = bindAll(button, [
4 {
5 type: 'click',
6 listener: onClick,
7 options: { passive: true },
8 },
9 // default options that are applied to all bindings
10 { capture: false },
11]);
12
13// when you are all done:
14unbind();
When using defaultOptions
for bindAll
, the defaultOptions
are merged with the options
on each binding. Options on the individual bindings will take precedent. You can think of it like this:
1const merged: AddEventListenerOptions = { 2 ...defaultOptions, 3 ...options, 4};
Note: it is a little bit more complicated than just object spreading as the library will also behave correctly when passing in a
boolean
capture argument. An options value can be a boolean{ options: true }
which is shorthand for{ options: {capture: true } }
Thanks to the great work by @Ayub-Begimkulov and @Andarist bind-event-listener
has fantastic TypeScript types and auto complete.
⚠️ TypeScript 4.1+ is required for types ⚠️ TypeScript 5.0+ is required for event name autocompletion
1import invariant from 'tiny-invariant'; 2import { bind } from 'bind-event-listener'; 3 4bind(window, { 5 type: 'click', 6 function: function onClick(event) { 7 // `event` is correctly typed as a 'MouseEvent' 8 // `this` is correctly typed as `window` (the event target that the event listener is added to) 9 }, 10}); 11 12const button = document.querySelector('button'); 13invariant(button instanceof HTMLElement); 14 15bind(button, { 16 type: 'click', 17 function: function onClick(event) { 18 // `event` is correctly typed as a 'MouseEvent' 19 // `this` is correctly typed as `button` (the event target that the event listener is added to) 20 }, 21}); 22 23const object = { 24 handleEvent: function onClick(event) { 25 // `event` is correctly typed as a 'MouseEvent' 26 // `this` is correctly typed as `object` (the event listener object that the event listener is added to) 27 }, 28}; 29 30bind(button, { 31 type: 'click', 32 function: object, 33});
bind
and bindAll
accept type arguments (generics), but it is generally best to let these be inferred
1// with explicit type arguments 2bind<HTMLElement, 'click'>(button, { 3 type: 'click', 4 listener: function onClick() {}, 5}); 6 7// ✨ types will automatically be inferred for you ✨ 8bind(button, { 9 type: 'click', 10 listener: function onClick() {}, 11}); 12 13// with explicit type arguments 14bindAll<HTMLElement, ['click', 'keydown']>(button, [ 15 { 16 type: 'click', 17 listener: function onClick() {}, 18 }, 19 { 20 type: 'keydown', 21 listener: function onKeyDown() {}, 22 }, 23]); 24 25// ✨ types will automatically be inferred for you ✨ 26bindAll(button, [ 27 { 28 type: 'click', 29 listener: function onClick() {}, 30 }, 31 { 32 type: 'keydown', 33 listener: function onKeyDown() {}, 34 }, 35]);
Typescript built in DOM types: raw view, pretty view (warning: pretty view seems to crash Github!)
1import { Binding, Listener, UnbindFn } from 'bind-event-listener';
Listener
: the function
or object
that you provide to the listener
property of a Binding
1bind(button, { 2 type: 'click', 3 listener: function onClick() {}, // ← `Listener` 4});
Binding
: the definition of an event binding.
1bind( 2 button, 3 // ↓ `Binding` 4 { 5 type: 'click', 6 listener: function onClick() {}, 7 }, 8);
UnbindFn
: a named type for () => void
to make it clearer that the function will unbind the added event listener(s):
1const unbind: UnbindFn = bind(button, { type: 'click', listener: function onClick() {} });
react
effectYou can return a cleanup function from useEffect
(or useLayoutEffect
). bind-event-listener
makes this super convenient because you can just return the unbind function from your effect.
1import React, { useState, useEffect } from 'react'; 2import { bind } from 'bind-event-listener'; 3 4export default function App() { 5 const [clickCount, onClick] = useState(0); 6 7 useEffect(() => { 8 const unbind = bind(window, { 9 type: 'click', 10 listener: () => onClick((value) => value + 1), 11 }); 12 13 return unbind; 14 }, []); 15 16 return <div>Window clicks: {clickCount}</div>; 17}
You can play with this example on codesandbox
Brought to you by @alexandereardon
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
Found 3/10 approved changesets -- score normalized to 3
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
13 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-06-30
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn MoreLast Day
1.8%
13,107
Compared to previous day
Last Week
-6.8%
365,069
Compared to previous week
Last Month
16%
1,566,131
Compared to previous month
Last Year
261.1%
12,355,862
Compared to previous year