Command Palette

Search for a command to run...

Hectal
PHASE 9Intermediate ~24 min· topic 5 of 8

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, altKey and metaKey.
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.

One click is many eventsdiagram
Rendering diagram…

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.

app.jswhole filejavascript
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.

app.jswhole filejavascript
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.

app.jswhole filejavascript
form.addEventListener("focusout", (event) => {
  validateField(event.target);
});

Try it yourself

  1. 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. 2

    Add Ctrl+S

    In the third example, add a keydown listener that logs saved when e.key === "s" and e.ctrlKey is true, and calls e.preventDefault(). Fire it with new KeyboardEvent("keydown", { key: "s", ctrlKey: true, bubbles: true, cancelable: true }). What would happen without preventDefault() in a real browser?

  3. 3

    Track the mouse

    In the second example, add a pointermove listener on the pad that writes e.offsetX and e.offsetY into the pad's text. Move your mouse over it.

Code & diagrams

See every event a click makes New tab

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

Press Run to see the page.

Console

Nothing logged yet.
Mouse and pointer event properties New tab

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

Press Run to see the page.

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
key versus code New tab

`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

Press Run to see the page.

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"
Focus, blur and focusin on a real form New tab

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

Press Run to see the page.

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.

terminal
$ the page shows
── what you'll see ──
On a German keyboard the shortcut fires on the key labelled Y instead; on French AZERTY it fires on the key labelled W.

Break #2

Remove the focus outline

Add *:focus { outline: none; } to the CSS of the focus example.

terminal
$ the page shows
── what you'll see ──
Pressing Tab moves focus, but nothing on screen shows which field or button is focused.

Break #3

Listen for focus on the form

Write form.addEventListener("focus", ...) to highlight whichever field is focused.

terminal
$ the page shows
── what you'll see ──
Nothing happens when you click into the fields. No error.

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) keydown fires with event.isComposing === true and key is often "Process". Check isComposing before acting on Enter, or you'll submit while the user is still choosing a character. For text, listen to input or beforeinput instead of keys.

  • ▸

    el.setPointerCapture(e.pointerId) in pointerdown makes all later pointer events go to that element even when the pointer leaves it, which keeps drags and sliders working. Use CSS touch-action to 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 click on mobile is gone in every modern browser for pages with <meta name="viewport" content="width=device-width">, so you don't need touchend tricks for fast taps.

Remember this

  1. 1

    Mouse events come from a mouse or trackpad. In order, one click produces mousedown (button pressed), mouseup (released), then click (pressed and released on the same element). A quick second click adds another mousedown, mouseup, click and then dblclick. event.detail counts the clicks in a row (1, 2, 3). button says which button: 0 main (usually left), 1 middle, 2 secondary (right, which also fires contextmenu). clientX/clientY give the position in the visible window in CSS pixels; offsetX/offsetY give it relative to the target. shiftKey, ctrlKey, altKey and metaKey (⌘ on a Mac) are true if those keys were held.

  2. 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/pointerout and pointerenter/pointerleave mirror the mouse ones, and add pointerType ("mouse", "touch" or "pen"), pointerId (to track several fingers) and pressure. The browser fires each pointer... event just before its mouse... twin. Prefer pointer events for anything you drag or draw. For plain buttons, click is still right: it fires for mouse, touch and the keyboard (Enter or Space on a <button>).

  3. 3

    Hover events come in two pairs. mouseover/mouseout bubble and also fire when the pointer moves onto a child, so they fire often. mouseenter/mouseleave don'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. 4

    Keyboard events fire on the element that has focus (or on <body> if nothing does), then bubble up to document. keydown fires when a key goes down, and again and again while it is held, with event.repeat set to true on the repeats. keyup fires once when it's released. (keypress is deprecated: don't use it.) Listen on document for page-wide shortcuts, and on an input for keys inside it.

  5. 5

    **key versus code**: event.key is what the key means with the current layout and modifiers: "a", "A" with Shift, "Enter", "ArrowLeft", "Escape", " " (a space). event.code is 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 gives key: "a" but code: "KeyQ". Use key for text and shortcuts named by letter (Ctrl+S). Use code for games, where WASD should stay in the same place on every layout. Never use the old keyCode/which numbers.

  6. 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 gets blur and focusout, the new one gets focus and focusin. focus/blur don't bubble; focusin/focusout do, so use them to react to focus anywhere inside a form. event.relatedTarget says where focus came from or is going to. document.activeElement is the focused element right now, and el.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

01

What is the difference between event.key and event.code? When would you use each?

02

Why are pointer events preferred over mouse and touch events?

03

What is the difference between focus/blur and focusin/focusout?

04

Which events fire, in order, when a user double-clicks a button?

Practice

01

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.

02

Show a #tip paragraph while a <input id="pwd"> has focus, and hide it when focus leaves.

Trade-offs

  • ↔

    click is simplest and accessible for buttons, but for dragging, drawing or press-and-hold you need the finer control of pointerdown/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 detail and button mean.

  • I use pointer events for drag and draw, and click for buttons.

  • I can choose between key and code, and read modifier keys.

  • I can skip shortcuts while the user types in a field.

  • I can track focus with focusin/focusout and keep focus visible.