Topic 9.5
Mouse, Keyboard and Focus Events
In one line
Pointer events (pointerdown, pointerup, click, dblclick) cover mouse, touch and pen; keyboard events (keydown, keyup) give you key (the character meant) and code (the physical key); and focus events (focus, blur, focusin, focusout) tell you which element will receive typing.
Think of it like this
A shop counter with three kinds of bell. The door bell rings when someone walks in (the pointer arrives), the counter bell rings when they tap it (a click), and the phone rings with a message you must listen to (a key press with a letter in it). Focus is which assistant is serving which customer right now: only one at a time, and when the customer moves on, that assistant is free again.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Pointer
- Anything that points at the screen: a mouse, a finger or a pen.
- pointerType
- Which kind of pointer caused the event:
"mouse","touch"or"pen". - clientX / clientY
- Where the pointer is, in pixels from the top-left of the visible window.
- Modifier keys
- Shift, Ctrl, Alt and Meta (⌘ or ⊞), read with
shiftKey,ctrlKey,altKeyandmetaKey. - key
- What a key press means: the character or name like
"a","A","Enter". - code
- Which physical key was pressed, like
"KeyA"or"Space", whatever the layout. - Focus
- Being the element that receives keyboard input right now. Only one element has it.
- Keyboard layout
- Which characters a keyboard's keys type, such as US QWERTY, German QWERTZ or French AZERTY.
- relatedTarget
- On focus and hover events, the other element involved: where focus or the pointer came from or went to.
Step by step
01One click is many events
Press and release a mouse button on a button. The browser fires pointer and mouse events for the press and release, then a click. A second quick click adds a dblclick at the end.
02Choose the right event
For a button's action: click (works for mouse, touch and keyboard). For dragging or drawing: pointerdown, pointermove, pointerup. For a right-click menu: contextmenu. For hover reactions: pointerenter/pointerleave.
03Read keys by meaning
A shortcut listener on document checks key and the modifiers. metaKey covers ⌘ on a Mac, ctrlKey covers Ctrl elsewhere.
document.addEventListener("keydown", (event) => {
if (event.key === "k" && (event.ctrlKey || event.metaKey)) {
event.preventDefault(); // stop the browser's own Ctrl+K
openSearch();
}
});04Don't steal keys from text boxes
A single-letter shortcut like / must not fire while someone is typing a / in a field. Check where the key went first.
document.addEventListener("keydown", (event) => {
if (event.target.closest("input, textarea, select, [contenteditable]")) return;
if (event.key === "/") {
event.preventDefault();
searchBox.focus();
}
});05Follow focus around a form
Moving from one field to the next fires blur and focusout on the old field, then focus and focusin on the new one. A focusout listener on the form is a good place to validate a field when the user leaves it.
form.addEventListener("focusout", (event) => {
validateField(event.target);
});Try it yourself
- 1
Compare a tap and a click
In the first example, predict which events appear for one mouse click. Then open the page on a phone or with DevTools device mode (touch) and tap: what changes?
- 2
Add Ctrl+S
In the third example, add a
keydownlistener that logssavedwhene.key === "s"ande.ctrlKeyis true, and callse.preventDefault(). Fire it withnew KeyboardEvent("keydown", { key: "s", ctrlKey: true, bubbles: true, cancelable: true }). What would happen withoutpreventDefault()in a real browser? - 3
Track the mouse
In the second example, add a
pointermovelistener on the pad that writese.offsetXande.offsetYinto the pad's text. Move your mouse over it.
Code & diagrams
This one needs you: click the button, double-click it and right-click it, and read the list. On a phone, tap it and watch `pointerType` say `touch`. Tab to the button and press Enter: only `click` appears, with `detail=0`.
Preview
Console
Nothing logged yet.The script builds the events itself with exact values, so the output never changes. Real events from your mouse carry the same properties with real values.
Preview
Console
Nothing logged yet.Expected console output
pointerdown | type: pen | button: 0 | at 40 25
click | detail: 1 | shift held: true
click | detail: 2 | shift held: false
dblclick | detail: 2
contextmenu | button: 2`JSON.stringify` puts quotes round the key so a space is visible. Now click the preview and type: hold a key down to see `repeat: true`.
Preview
Console
Nothing logged yet.Expected console output
keydown key: "a" | code: KeyA | shift: false | repeat: false
keydown key: "A" | code: KeyA | shift: true | repeat: false
keydown key: "z" | code: KeyY | shift: false | repeat: false
keydown key: " " | code: Space | shift: false | repeat: false
keydown key: "Enter" | code: Enter | shift: false | repeat: true
keyup key: "Enter"Click into a field, then press Tab and Shift+Tab. Leaving a field empty turns it red. `relatedTarget` names the field focus came from.
Preview
Console
Nothing logged yet.Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Use code for a typed character
A search shortcut checks event.code === "KeyZ" for "Z" and a French or German user presses the key labelled Z.
Break #2
Remove the focus outline
Add *:focus { outline: none; } to the CSS of the focus example.
Break #3
Listen for focus on the form
Write form.addEventListener("focus", ...) to highlight whichever field is focused.
Myth vs fact
Myth
click is only for the mouse.
Fact
click also fires for a tap on a touch screen and for Enter or Space on a focused <button> (Enter on a link). That's why real <button> elements are the accessible choice.
Myth
keyCode is the reliable way to read keys.
Fact
keyCode and which are deprecated numbers that differ between browsers and layouts. Use key for meaning and code for physical position.
Myth
Firing a keydown from code types a character into an input.
Fact
Synthetic keyboard events run your listeners but don't trigger the browser's default actions like inserting text. To change a field from code, set value and fire an input event.
Myth
Touch screens need touchstart and touchend.
Fact
Pointer events cover touch, mouse and pen with one API in every current browser. The touch events still exist, but you rarely need them.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
During text composition (typing Chinese, Japanese or Korean with an IME, or some mobile keyboards)
keydownfires withevent.isComposing === trueandkeyis often"Process". CheckisComposingbefore acting on Enter, or you'll submit while the user is still choosing a character. For text, listen toinputorbeforeinputinstead of keys. - ▸
el.setPointerCapture(e.pointerId)inpointerdownmakes all later pointer events go to that element even when the pointer leaves it, which keeps drags and sliders working. Use CSStouch-actionto tell the browser which gestures (pan, zoom) it may still handle. - ▸
High-frequency events (
pointermove,mousemove,wheel,scroll) can fire more often than the screen refreshes. Browsers coalesce them to about once per frame;e.getCoalescedEvents()returns the in-between points for smooth drawing. Keep these listeners cheap or throttle them (Topic 9.7). - ▸
The old 300 ms delay before
clickon mobile is gone in every modern browser for pages with<meta name="viewport" content="width=device-width">, so you don't needtouchendtricks for fast taps.
Remember this
- 1
Mouse events come from a mouse or trackpad. In order, one click produces
mousedown(button pressed),mouseup(released), thenclick(pressed and released on the same element). A quick second click adds anothermousedown,mouseup,clickand thendblclick.event.detailcounts the clicks in a row (1, 2, 3).buttonsays which button: 0 main (usually left), 1 middle, 2 secondary (right, which also firescontextmenu).clientX/clientYgive the position in the visible window in CSS pixels;offsetX/offsetYgive it relative to the target.shiftKey,ctrlKey,altKeyandmetaKey(⌘ on a Mac) aretrueif those keys were held. - 2
Pointer events are the modern, unified version: one set of events for a mouse, a finger or a pen.
pointerdown,pointermove,pointerup,pointercancel,pointerover/pointeroutandpointerenter/pointerleavemirror the mouse ones, and addpointerType("mouse","touch"or"pen"),pointerId(to track several fingers) andpressure. The browser fires eachpointer...event just before itsmouse...twin. Prefer pointer events for anything you drag or draw. For plain buttons,clickis still right: it fires for mouse, touch and the keyboard (Enter or Space on a<button>). - 3
Hover events come in two pairs.
mouseover/mouseoutbubble and also fire when the pointer moves onto a child, so they fire often.mouseenter/mouseleavedon't bubble and fire only when the pointer enters or leaves the element as a whole, children included. For simple hover styling, use CSS:hover; use the events when JavaScript must react, like showing a preview. - 4
Keyboard events fire on the element that has focus (or on
<body>if nothing does), then bubble up todocument.keydownfires when a key goes down, and again and again while it is held, withevent.repeatset totrueon the repeats.keyupfires once when it's released. (keypressis deprecated: don't use it.) Listen ondocumentfor page-wide shortcuts, and on an input for keys inside it. - 5
**
keyversuscode**:event.keyis what the key means with the current layout and modifiers:"a","A"with Shift,"Enter","ArrowLeft","Escape"," "(a space).event.codeis which physical key was pressed, named after its position on a US keyboard:"KeyA","Digit1","Space","ShiftLeft". On a French AZERTY keyboard, pressing the key labelled A giveskey: "a"butcode: "KeyQ". Usekeyfor text and shortcuts named by letter (Ctrl+S). Usecodefor games, where WASD should stay in the same place on every layout. Never use the oldkeyCode/whichnumbers. - 6
Focus is which element receives keyboard input. Links, buttons and form fields can be focused by clicking or pressing Tab; other elements need
tabindex="0". When focus moves, the old element getsblurandfocusout, the new one getsfocusandfocusin.focus/blurdon't bubble;focusin/focusoutdo, so use them to react to focus anywhere inside a form.event.relatedTargetsays where focus came from or is going to.document.activeElementis the focused element right now, andel.focus()/el.blur()move focus from code. Never remove the visible focus outline without a replacement (use CSS:focus-visible, see/css): keyboard users need it to know where they are.
Explain it without notes
What is the difference between event.key and event.code? When would you use each?
Why are pointer events preferred over mouse and touch events?
What is the difference between focus/blur and focusin/focusout?
Which events fire, in order, when a user double-clicks a button?
Practice
Make arrow keys move a 30 px square #player 10 px at a time (left and right), using transform. Test with two dispatched ArrowRight presses and log the position.
Show a #tip paragraph while a <input id="pwd"> has focus, and hide it when focus leaves.
Trade-offs
- ↔
clickis simplest and accessible for buttons, but for dragging, drawing or press-and-hold you need the finer control ofpointerdown/pointermove/pointerup, plus pointer capture and keyboard alternatives. - ↔
Single-key shortcuts are fast for power users but can clash with assistive technology and typing; WCAG 2.1.4 asks that they can be turned off or remapped, or only work when a component has focus. Modifier shortcuts (Ctrl+K) are safer.
Done when you can
I know the order of pointer, mouse and click events and what
detailandbuttonmean.I use pointer events for drag and draw, and
clickfor buttons.I can choose between
keyandcode, and read modifier keys.I can skip shortcuts while the user types in a field.
I can track focus with
focusin/focusoutand keep focus visible.