How Typing Indicators Actually Work (They're More Interesting Than You Think)
You're staring at your screen. Three little dots are bouncing... bouncing... bouncing... and then they disappear. No message.
We've all been there. But have you ever wondered how those typing indicators actually work under the hood? It seems simple: "User A presses key -> Show indicator to User B". But in reality, it's a fascinating combination of WebSockets, debouncing, and state management.
The Naive Approach (And Why It Fails)
When most developers first try to build a typing indicator, they do something like this:
input.addEventListener('keydown', () => {
socket.emit('typing', { userId: 123 });
});
Do you see the problem here? If someone types "Hello world" at 60 WPM, they are hitting the keyboard multiple times a second. You are firing a WebSocket event for every single keystroke. Your server will be hammered with events.
The Solution: Throttling and Debouncing
To fix this, we need to send fewer events. We use two concepts: Throttling (for starting) and Debouncing (for stopping).
When the user starts typing, we immediately send a "typing_start" event. But as they continue typing, we don't send anything else. We reset a timer on every keystroke. If the user hasn't pressed a key for a few seconds, the timer finally fires and sends a "typing_stop" event.
let typingTimeout;
let isTyping = false;
function handleTyping() {
if (!isTyping) {
isTyping = true;
socket.emit('typing_start');
}
clearTimeout(typingTimeout);
typingTimeout = setTimeout(() => {
isTyping = false;
socket.emit('typing_stop');
}, 2000);
}
Handling Edge Cases
If you build this for a production app, you'll quickly run into fun edge cases:
- What if the user disconnects while typing? Their "typing_stop" event never fires! The receiver's client needs to auto-clear indicators after a few seconds of no updates.
- Multiple users in a group chat? You need to keep an array or set of users currently typing, not just a boolean.
- Blurring the window: If the user switches tabs, you should immediately send a "typing_stop" instead of waiting for the timeout.
Conclusion
The next time you see those three bouncing dots, take a moment to appreciate the WebSockets flying back and forth, and the timers meticulously keeping track of every pause in keystrokes.
Hit me up on X with the links below if you want to discuss pretty much anything. Thank you for reading!