cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Mouse, pointer & touch

Handle clicks, hovers, drags, pens, and touch screens with mouse events, pointer events, pointer capture, and HTML drag and drop.

By the end, you can
  • 01
    Read mouse button dataUse button, buttons, relatedTarget, and click-family events accurately.
  • 02
    Choose pointer eventsHandle mouse, pen, and touch with one event model and know when compatibility mouse events appear.
  • 03
    Build reliable draggingUse pointer capture or HTML drag and drop depending on the interface.

One vocabulary for pointing at things

Interfaces used to be designed for a mouse first: move the cursor, press a button, release it, maybe double-click. Phones, tablets, drawing pens, trackpads, and hybrid laptops changed the job. A modern web app needs to answer the same question for many devices: where is the pointer, what is it doing, and should this page react?

This lesson gives you three layers of tools. Mouse events are still important for ordinary clicks, hover, and right-click menus. Pointer events are the newer general-purpose API for mouse, pen, and touch. HTML drag and drop is a specialized browser feature for moving draggable items into drop zones.

Real-life analogyPointer events are a universal remote

Instead of writing one control path for a mouse and a different one for a finger, pointer events give you one set of buttons. The event tells you which device pressed the button.

In real life: One remote with shared buttons
In JavaScript: pointerdown, pointermove, and pointerup
In real life: TV, speaker, or projector mode
In JavaScript: pointerType: mouse, pen, or touch
In real life: A device-specific extra, like stylus pressure
In JavaScript: Properties such as pressure, when hardware reports them

Where the analogy stops: A real universal remote can control devices at once. A pointer event describes one pointer stream at a time; multi-touch uses separate pointerId values.

Definition

A pointer is an input point on the page: a mouse cursor, a finger touching the screen, or a pen tip. Pointer events report that point with device details.

Mouse events & buttons

INTERACTIVE

A primary mouse click is not one event. In most browsers, a normal click produces a sequence like pointerdown, mousedown, pointerup, mouseup, then click. Middle and secondary buttons may also produce auxclick or contextmenu. Use dblclick only when the double activation itself matters.

Two properties are easy to confuse. button names the button that changed for this event: 0 main, 1 middle/auxiliary, 2 secondary. buttons is a bitmask of all buttons currently held: 1 primary, 2 secondary, 4 auxiliary. During mousemove or pointermove, buttons usually matters more than button.

Pointer inspector pad
Read the eventPop out in the code editor (opens in a new tab)JavaScript
pad.addEventListener("pointermove", (event) => {  show("pointerType", event.pointerType);  show("pointerId", event.pointerId);  show("isPrimary", event.isPrimary);  show("button", event.button);  show("buttons", event.buttons);  show("pressure", event.pressure);});
Live padbutton vs buttons
Move or press here
pointerType
move or press inside the pad
pointerId
—
isPrimary
—
button/buttons
—
client / offset
—
pressure
—
Legend: button 0 main, 1 middle/aux, 2 secondary. buttons bitmask 1 primary, 4 auxiliary, 2 secondary.
    Try it yourself

    Try primary, middle, and secondary buttons. Keyboard users can Tab to the pad, then use Enter or Space on the buttons below.

    Real browser events fill the table. A regular click usually logs pointerdown → mousedown → pointerup → mouseup → click; right and middle buttons add events such as contextmenu or auxclick in most browsers.

    This uses React event handlers for display, but the event names and properties are the browser’s mouse and pointer events. Pen and touch data depends on your device.

    If you need a custom right-click menu, listen for contextmenu, not only mousedown. If you suppress the browser menu with preventDefault(), provide another way for keyboard and assistive-technology users to reach the same actions. The next lesson, Keyboard & focus, picks up that accessibility thread.

    Step through button and buttons
    Step 0 of 6Ready
    Your turn: follow the blue line

    Switch the button type, predict the two numbers, then step through the event object.

    Running in
    1. script
    Next: line 1
    Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
      pointerType: "mouse",  pointerId: 1,  isPrimary: true,  button: 0,  buttons: 1,}; console.log(event.pointerType);console.log(event.button);console.log(event.buttons);
    CallStoreChangeResultRun = next line. Ran = already executed.
    Recent returnsNothing yet. Start with the blue line.
    Change the pointer event

    Changing the choice starts a fresh replay.

    A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

    mouseover vs mouseenter

    INTERACTIVE

    Hover events are about boundaries. mouseover and mouseout bubble, so a parent can hear movement involving its children. They also carry relatedTarget, the element the pointer came from or is going to. That is useful for event delegation, but noisy for a card with nested icons and text.

    Real-life analogyA house with a loud doorbell

    If the visitor only cares that they entered the house, use the once-per-house signal. If you want a parent to hear about movement through rooms, use the bubbling signal.

    In real life: Doorbell rings entering the house
    In JavaScript: mouseenter fires when the pointer enters the element
    In real life: Doorbell rings again in each room
    In JavaScript: mouseover bubbles as the pointer crosses children
    In real life: Looking back at the previous room
    In JavaScript: relatedTarget points to where the pointer came from

    Where the analogy stops: A real house has physical rooms. In the DOM, a tiny SVG path, text node boundary, or nested button can act like another room for events.

    Nested hover: doorbell or house entry?
    Two hover listenersPop out in the code editor (opens in a new tab)JavaScript
    const parent = document.querySelector(".card"); parent.addEventListener("mouseover", (event) => {  console.log("over", event.target.className);  console.log("from", event.relatedTarget?.className ?? "outside");}); parent.addEventListener("mouseenter", () => {  console.log("entered the whole card");});
    Nested cardmouseover 0 · mouseenter 0
    🏠House card
      Try it yourself

      Move slowly across the emoji, title, and button inside the card.

      mouseover/mouseout bubble as you cross child boundaries. mouseenter/mouseleave describe entering or leaving the whole card.

      The log shows relatedTarget when the browser provides it; moving from outside often reports outside.

      Pointer events have matching hover names: pointerover/pointerout bubble, while pointerenter/pointerleave do not. Choose the mouse version when you only care about mouse compatibility; choose pointer versions when the same logic belongs with a pointer-driven widget.

      Pointer events

      UNIVERSAL

      Pointer events include pointerdown, pointermove, pointerup, pointercancel, pointerover, pointerout, pointerenter, and pointerleave. They look a lot like mouse events, but add pointerId, pointerType, isPrimary, pressure, and other hardware-aware properties.

      Browsers fire compatibility mouse events after pointer events for most inputs, especially so older mouse-based code still works. That means you should not blindly handle both pointerdown and mousedown for the same action, or you may run it twice. Pick pointer events for custom drawing, sliders, resizing, and gestures.

      When pointercancel appears

      pointercancel means the browser stopped sending that pointer stream to your code. A common cause is touch scrolling or zooming. For a custom draggable surface, CSS touch-action: none tells the browser your component handles that gesture.

      Choosing an event family
      QuestionUseDetailsWhen it fits
      Changed buttonevent.button0 main, 1 middle/auxiliary, 2 secondaryAsk: which button caused this event?
      Held buttonsevent.buttonsBitmask: 1 primary, 2 secondary, 4 auxiliaryAsk: what is still down during a move?
      Nested hovermouseover / mouseoutBubble and include relatedTargetGood for delegation or one handler on a parent.
      Whole hovermouseenter / mouseleaveDo not bubbleGood when child elements should not restart hover.
      Universal inputpointerdown / pointermove / pointerupMouse, pen, and touch with pointerTypeGood for drawing, sliders, resizing, and gestures.
      Native card transferHTML DnDdragstart, dragover, drop, dataTransferGood for desktop-like item movement; touch support varies.

      Pointer capture

      INTERACTIVE

      Dragging is fragile if the pointer must stay exactly over the tiny thing being dragged. A fast hand can leave a slider thumb or resize handle before the next move event. setPointerCapture(event.pointerId) retargets later pointer events for that same pointer to the capturing element until release. Browsers automatically release capture after pointerup, and you can also call releasePointerCapture().

      Real-life analogyPointer capture is holding a kite string

      You do not need the pointer to stay on the thumb. As long as you hold the string, the thumb can keep following the pointer.

      In real life: Your hand keeps the string
      In JavaScript: The element keeps receiving that pointer’s events
      In real life: The kite drifts away
      In JavaScript: The pointer may move outside the element
      In real life: Letting go
      In JavaScript: pointerup or releasePointerCapture() ends capture

      Where the analogy stops: A kite string can pull back on the kite. Pointer capture does not move the pointer; it only changes which element receives subsequent events.

      Pointer capture slider
      Capture the pointerPop out in the code editor (opens in a new tab)JavaScript
      thumb.addEventListener("pointerdown", (event) => {  thumb.setPointerCapture(event.pointerId);  drag(event.clientX);}); thumb.addEventListener("pointermove", (event) => {  if (event.buttons === 1) drag(event.clientX);}); thumb.addEventListener("pointerup", (event) => {  thumb.releasePointerCapture(event.pointerId);});
      Custom slider35%
        Try it yourself

        With capture on, the thumb keeps receiving pointer moves for that pointer until pointerup, even if you drag outside the thumb.

        The slider sets touch-action: none so a touch drag is treated as the component’s gesture instead of page scrolling.
        The essential patternPop out in the code editor (opens in a new tab)JavaScript
        thumb.addEventListener("pointerdown", (event) => {  thumb.setPointerCapture(event.pointerId);  drag(event.clientX);}); thumb.addEventListener("pointermove", (event) => {  if (event.buttons === 1) drag(event.clientX);}); thumb.addEventListener("pointerup", (event) => {  thumb.releasePointerCapture(event.pointerId);});

        Drag and drop

        INTERACTIVE

        HTML drag and drop is a separate API for moving data between a draggable source and a drop target. Set draggable="true", write data in dragstart with event.dataTransfer.setData(), allow a target by calling preventDefault() in dragover (and often dragenter), then read the data in drop. The data store is protected while dragging, so custom data is reliably readable in drop, not during dragover.

        Real-life analogyDrag and drop is a moving company

        The browser will not deliver a box to an address unless the address says it accepts deliveries. That is the surprising job of dragover.

        In real life: dragstart packs the box
        In JavaScript: dataTransfer.setData() stores the card id
        In real life: dragover accepts the address
        In JavaScript: preventDefault() says this target accepts drops
        In real life: drop unpacks
        In JavaScript: Read the id and move the element or update state
        In real life: dragend closes the job
        In JavaScript: Clean up visual state whether the drop worked or not

        Where the analogy stops: Moving companies work for every package. Browser drag and drop is mouse-oriented; touch support varies, so many apps build touch-friendly dragging with pointer events and capture instead.

        Drag and drop moving company
        Allow the deliveryPop out in the code editor (opens in a new tab)JavaScript
        card.draggable = true; card.addEventListener("dragstart", (event) => {  event.dataTransfer.setData("text/plain", card.id);}); target.addEventListener("dragover", (event) => {  event.preventDefault();}); target.addEventListener("drop", (event) => {  const id = event.dataTransfer.getData("text/plain");  target.append(document.getElementById(id));});
        Two listsnative DnD
        Try it yourself

        Use a mouse or trackpad. Many touch devices do not run HTML drag and drop the same way.

        Drag a card to another list.

        The lists are built with DOM APIs inside an empty ref container, so React is not asked to manage nodes that the browser reorders during the drag.
        Native drag and drop skeletonPop out in the code editor (opens in a new tab)JavaScript
        card.draggable = true; card.addEventListener("dragstart", (event) => {  event.dataTransfer.setData("text/plain", card.id);}); target.addEventListener("dragover", (event) => {  event.preventDefault();}); target.addEventListener("drop", (event) => {  const id = event.dataTransfer.getData("text/plain");  target.append(document.getElementById(id));});

        Where you’ll use this

        PRACTICAL

        Real front-end work often mixes these APIs. A design tool canvas uses pointer events for mouse, pen, and touch. A splitter captures the pointer so it keeps resizing even when your hand outruns the handle. A file manager might use HTML drag and drop for desktop cards, but a pointer-event implementation for touch screens.

        Pointer-first drawing or resizingPop out in the code editor (opens in a new tab)JavaScript
        element.addEventListener("pointerdown", (event) => {  if (event.button !== 0) return;  element.setPointerCapture(event.pointerId);}); element.addEventListener("pointermove", (event) => {  if (event.buttons !== 1) return;  drawLineTo(event.clientX, event.clientY);});
        Which event should this feature use?
        • Highlight a menu when the pointer enters the whole menu, without flicker over child icons
        • Draw with a mouse, finger, or pen
        • Move cards between lists with the browser’s built-in drop feedback
        • Open a custom right-click menu
        • Make a brush thicker when a stylus presses harder
        • Let a card carry an id to a drop zone
        • Show a tooltip once when entering a button that contains an SVG
        • Detect the mouse wheel button opening a special action
        Try it yourself
        0 of 8 correct

        Sort each product requirement by the event family it needs most.

        Choose a category for every card. You can change an answer at any time; Reset clears them all.

        Common misconceptions

        • “Pointer events are CSS pointer-events.” No. The JavaScript API is events such as pointerdown; the CSS property controls hit-testing.
        • “button and buttons are the same.” No. One changed; the other is a held-button bitmask.
        • “mouseenter bubbles like mouseover.” It does not. Use mouseover for delegation.
        • “Pointer capture captures every pointer.” It captures one pointerId for one element.
        • “HTML drag and drop works the same on every touch device.” It does not. Hedge, test, and consider pointer events for custom touch dragging.
        • “Calling drop is enough.” The browser normally requires preventDefault() during dragover before a drop target accepts the drop.

        Practice exercises

        5 EXERCISES
        Exercise 1 · Warm-upRead the button numbers
        Predict the two console lines.
        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const button = 2;
        const buttons = 3;
        console.log(button);
        console.log(buttons);

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 2 · Warm-upChoose the no-flicker hover event
          A card contains an icon, title, and button. Which event avoids restarting hover when moving between the children?

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 3 · PracticeAllow a drop
            Why does a drop zone need preventDefault() in dragover? Predict this simplified output.
            Starter codePop out in the code editor (opens in a new tab)JavaScript
            let canDrop = false;
            const event = { preventDefault() { canDrop = true; } };
            event.preventDefault();
            console.log(canDrop);

            Answer, then press Check. Spacing and letter case don’t matter.

              Exercise 4 · PracticeFix the runaway slider
              A custom slider stops moving when the pointer leaves the thumb. Which method should line 2 call?

              Answer, then press Check. Spacing and letter case don’t matter.

                Exercise 5 · ChallengeClamp a slider position
                Predict the percent for a pointer at clientX 175 on a track that starts at 100 and is 200 pixels wide.
                Starter codePop out in the code editor (opens in a new tab)JavaScript
                function percent(clientX, left, width) {
                  const raw = ((clientX - left) / width) * 100;
                  return Math.max(0, Math.min(100, Math.round(raw)));
                }
                console.log(percent(175, 100, 200));

                Answer, then press Check. Spacing and letter case don’t matter.

                  Check your understanding

                  7 QUESTIONS
                  Mouse, pointer & touch quiz · 7 questionsScore: first tries count
                  1. Question 1 of 7Which pair is correct for a normal primary mouse click in most browsers?

                    Choose an answer to see the explanation.

                  2. Question 2 of 7What does this print?

                    Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                    const event = { button: 1, buttons: 4 };
                    console.log(event.button);
                    console.log(event.buttons);

                    Choose an answer to see the explanation.

                  3. Question 3 of 7Why can mouseover fire several times while you are still inside one card?

                    Choose an answer to see the explanation.

                  4. Question 4 of 7What should you set on a custom touch slider so the browser does not take over the drag for scrolling?

                    Choose an answer to see the explanation.

                  5. Question 5 of 7What does this dragover-style program print?

                    Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
                    let allowed = false;
                    const event = { preventDefault() { allowed = true; } };
                    event.preventDefault();
                    console.log(allowed);

                    Choose an answer to see the explanation.

                  6. Question 6 of 7When can dataTransfer.getData() reliably read custom drag data?

                    Choose an answer to see the explanation.

                  7. Question 7 of 7Which event should you listen for to build a custom right-click menu?

                    Choose an answer to see the explanation.

                  Key takeaways

                  • Mouse events still matter for click, hover, auxiliary click, and context-menu behavior.
                  • button says what changed; buttons says what is held.
                  • mouseover/mouseout bubble; mouseenter/mouseleave do not.
                  • Pointer events are the default choice for custom controls that should work with mouse, pen, and touch.
                  • Pointer capture keeps one pointer stream going to one element during a drag.
                  • HTML drag and drop needs dragover plus preventDefault(), and touch behavior varies.

                  Final definition: Pointer events are browser events that describe one mouse, pen, or touch input point with a shared event vocabulary.

                  Up next: Keyboard & focus.

                  CompleteFrontend Clear concepts. Working examples.