How to Execute a Function After the User Stops Typing in JavaScript
Nick Scialli
March 04, 2021
Executing a function after a certain amount of inactivity is known as debouncing. Debouncing can be helpful for many reasons. One of the most popular applications in web development is to execute a search or filter some results after a user has stopped typing text in a textbox.
A Quick Example: Filtering Cities
Let’s say we have a list of cities in our document we want to filter. We don’t want to execute the filter function constantly, but only after the user is “done” typing. Since we don’t truly know when the user is done, we can make a guess that if the user pauses for one second, we are safe to execute the function. (This may vary depending on your use case).
Ultimately, we want our effect to look like this:
Our corresponding HTML looks like this:
<body>
<input type="text" id="city-filter" />
<ul id="city-list">
<li>Boston</li>
<li>New Brunswick</li>
<li>New York</li>
<li>Philadelphia</li>
<li>Washington</li>
<li>Wilmington</li>
</ul>
</body>
How This Will Work
The idea behind debouncing is that we have a global JavaScript variable that will hold a reference to a setTimeout
.
Then, we have a keyup
event listener on our input
. When this event is fired, we clear the global timer (if it’s running). This means the timer will only fire if it doesn’t get cleared before the specified timeout—in other words, it only fires if there is no keyup
event before the timeout!
Here’s how this looks in JavaScript.
let timer;
const input = document.querySelector('#city-filter');
input.addEventListener(function (e) {
// Clears any outstanding timer
clearTimeout(timer);
// Sets new timer that may or may not get cleared
timer = setTimeout(() => {
// Only fires if not cleared
}, 1000);
});
Filling in the Blanks for Our Use Case
Now all we have to do is fill in the blanks for our use case. I’ll do this by iterating over all the children
of the ul #city-list
element and updating the style.display
property accordingly.
let timer;
const input = document.querySelector('#city-filter');
input.addEventListener(function (e) {
// Clears any outstanding timer
clearTimeout(timer);
// Sets new timer that may or may not get cleared
timer = setTimeout(() => {
const items = document.querySelector('#city-list').children;
for (let item of items) {
item.style.display = item.textContent.includes(e.target.value)
? 'list-item'
: 'none';
}
}, 1000);
});
And that’s really it!
The Entire Code
The code for a full application you can run yourself is as follows:
<!DOCTYPE html>
<html>
<head>
<title>Debouncing in JavaScript</title>
<meta charset="UTF-8" />
</head>
<body>
<input type="text" id="city-filter" />
<ul id="city-list">
<li>Boston</li>
<li>New Brunswick</li>
<li>New York</li>
<li>Philadelphia</li>
<li>Washington</li>
<li>Wilmington</li>
</ul>
<script>
let timer;
const input = document.querySelector('#city-filter');
input.addEventListener('keyup', function (e) {
clearTimeout(timer);
timer = setTimeout(() => {
const items = document.querySelector('#city-list').children;
for (let item of items) {
item.style.display = item.textContent.includes(e.target.value)
? 'list-item'
: 'none';
}
}, 1000);
});
</script>
</body>
</html>
And you can see it in action on CodeSandbox.
Nick Scialli is a senior UI engineer at Microsoft.