Have you ever bought a new mechanical keyboard only to discover a dead switch two weeks later — past the return window? Or spilled coffee on your laptop and wondered which keys survived?
I built a free keyboard tester that runs entirely in the browser. No downloads, no backend, no data collection. Just open the page, press keys, and see which ones work.
In this post, I'll walk through the key technical decisions and JavaScript patterns I used to build it.
The Core Idea
Display a virtual keyboard on screen. When the user presses a physical key, the corresponding virtual key lights up. Simple concept, but there are a few tricky parts:
- Mapping physical keys to virtual keys — Not all keyboards have the same layout
- Capturing ALL key presses — Including Tab, F-keys, and other keys browsers like to hijack
- Counting keystrokes — For detecting chattering (double-firing keys)
- N-Key Rollover testing — Tracking multiple simultaneous key holds
Key-to-Element Mapping
Each virtual key in the HTML has a data-key attribute matching the KeyboardEvent.code value:
<div class="key" data-key="KeyA">A</div>
<div class="key" data-key="Space">Space</div>
<div class="key" data-key="ShiftLeft">Shift</div>
I chose event.code over event.key because code represents the physical key position, not the character it produces. This means the tester works regardless of keyboard language or layout (QWERTY, AZERTY, Dvorak, etc).
function getKeyElement(code) {
return document.querySelector('.key[data-key="' + code + '"]');
}
Capturing Every Key Press
Browsers intercept certain keys by default: Tab switches focus, F5 refreshes, F11 toggles fullscreen. To capture these, I use preventDefault() on both keydown and keyup events, with useCapture: true:
document.addEventListener('keydown', function(e) {
e.preventDefault();
e.stopPropagation();
const code = e.code;
const keyEl = getKeyElement(code);
if (keyEl) {
keyEl.classList.add('active'); // Visual press feedback
if (!testedKeys.has(code)) {
testedKeys.add(code);
keyEl.classList.add('tested'); // Permanent "tested" state
updateStats();
}
}
return false;
}, true); // useCapture = true
And the corresponding keyup handler to remove the "active" visual state:
document.addEventListener('keyup', function(e) {
e.preventDefault();
e.stopPropagation();
const keyEl = getKeyElement(e.code);
if (keyEl) keyEl.classList.remove('active');
return false;
}, true);
Preventing Browser Shortcuts
Some keys need extra prevention at the window level:
window.addEventListener('keydown', function(e) {
if (e.key === 'Tab' || e.key === 'F1' || e.key === 'F5' ||
e.key === 'F11' || e.key === 'F12') {
e.preventDefault();
}
});
This catches Tab (focus switching), F1 (help), F5 (reload), and F11/F12 (fullscreen/devtools) before the browser processes them.
The Keystroke Counter
This was a recent addition and probably the most useful feature for diagnosing keyboard problems. Mechanical keyboards can develop "chattering" — where one press registers as two or more inputs. This is caused by worn switch contacts bouncing.
The counter tracks every key press individually:
const keyCounts = {};
let totalKeystrokes = 0;
// Inside keydown handler:
keyCounts[code] = (keyCounts[code] || 0) + 1;
totalKeystrokes++;
updateKeystrokeUI(code, label);
The UI dynamically creates a card for each key, showing its press count. If a key registers 3+ presses, it's highlighted in amber as a potential chattering issue:
function updateKeystrokeUI(code, label) {
let entry = document.getElementById('kc-' + code);
if (!entry) {
entry = document.createElement('div');
entry.id = 'kc-' + code;
entry.className = 'flex items-center justify-between ...';
entries.appendChild(entry);
}
const count = keyCounts[code];
const isHigh = count >= 3;
entry.innerHTML = '<span class="' + (isHigh ? 'text-amber-400' : 'text-slate-300') + '">'
+ label + '</span><span>' + count + (isHigh ? ' !' : '') + '</span>';
}
The reset function clears all counts without affecting the main keyboard test state:
window.resetKeystrokeCounter = function() {
for (var k in keyCounts) delete keyCounts[k];
totalKeystrokes = 0;
document.getElementById('keystroke-entries').innerHTML = '';
};
Progress Tracking
Users need to know how many keys they've tested out of the total. The stats panel shows tested/total/percentage and color-codes the progress:
function updateStats() {
const tested = testedKeys.size;
const pct = Math.round((tested / totalKeysCount) * 100);
document.getElementById('keys-pressed').textContent = tested;
document.getElementById('keys-percent').textContent = pct + '%';
// Color feedback
const pctEl = document.getElementById('keys-percent');
if (pct >= 100) {
pctEl.className = '... text-emerald-400'; // Green = done
} else if (pct >= 50) {
pctEl.className = '... text-yellow-400'; // Yellow = halfway
}
}
Virtual Key Clicks
Not everyone has a physical keyboard handy (maybe they're testing remotely). Virtual keys are clickable too:
allKeys.forEach(function(keyEl) {
keyEl.addEventListener('click', function() {
const code = this.getAttribute('data-key');
this.classList.add('active');
if (!testedKeys.has(code)) {
testedKeys.add(code);
this.classList.add('tested');
updateStats();
}
// Keystroke counter for clicks too
keyCounts[code] = (keyCounts[code] || 0) + 1;
totalKeystrokes++;
setTimeout(() => this.classList.remove('active'), 200);
});
});
Lessons Learned
event.code>event.key— Always usecodefor physical key identification.keychanges with language/layout.useCapture: trueis essential — Without it, some keydown events get swallowed before your handler runs.A Set is perfect for tracking tested keys — O(1) lookups, no duplicates, and
.sizegives you the count for free.Chattering detection needs a counter, not a boolean — Just knowing a key "was pressed" isn't enough. You need to know how many times it registered per intended press.
No framework needed — The entire tool is vanilla HTML + CSS + JS. It loads instantly and works offline. Sometimes the simplest stack is the best stack.
Try It
The keyboard tester is live at toolknit.com/tools/keyboard-tester.html. It's part of ToolKnit, a collection of 30+ free browser-based tools for files, images, video, and more.
If you have a keyboard collecting dust, plug it in and test it. You might be surprised what you find.
Have you built similar browser-based utilities? I'd love to hear about the edge cases you ran into. Drop a comment below!
Top comments (0)