React Cheatsheet

Events

Use this React reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Synthetic Events

React wraps native DOM events in SyntheticEvent — a cross-browser wrapper with the same interface as native events.

function Example() {
  const handleClick = (e) => {
    console.log(e.type);          // 'click'
    console.log(e.target);        // DOM node
    console.log(e.currentTarget); // element with the listener
    e.preventDefault();           // prevent default browser action
    e.stopPropagation();          // stop bubbling
  };
  return <button onClick={handleClick}>Click</button>;
}

React 17+ attaches event listeners to the root container (not document), enabling multiple React roots on one page.

Attaching Event Handlers

// Inline arrow function (creates new fn each render)
<button onClick={() => doSomething()}>Click</button>

// Reference to handler (preferred for performance)
function MyButton() {
  const handleClick = () => doSomething();
  return <button onClick={handleClick}>Click</button>;
}

// Passing arguments
<button onClick={() => deleteItem(id)}>Delete</button>

// Handler with event AND argument
<button onClick={(e) => handleSelect(e, id)}>Select</button>

Mouse Events

EventFires when
onClickElement is clicked
onDoubleClickElement is double-clicked
onMouseDownMouse button pressed
onMouseUpMouse button released
onMouseMoveMouse moves over element
onMouseEnterMouse enters element (does not bubble)
onMouseLeaveMouse leaves element (does not bubble)
onMouseOverMouse enters element or child (bubbles)
onMouseOutMouse leaves element or child (bubbles)
onContextMenuRight-click
function Tracker() {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  return (
    <div
      onMouseMove={e => setPos({ x: e.clientX, y: e.clientY })}
      onMouseEnter={() => console.log('enter')}
      onMouseLeave={() => console.log('leave')}
    >
      {pos.x}, {pos.y}
    </div>
  );
}

Keyboard Events

EventFires when
onKeyDownKey is pressed down
onKeyUpKey is released
onKeyPress(deprecated) Key press with char value
function SearchInput() {
  const handleKeyDown = (e) => {
    if (e.key === 'Enter') search(e.target.value);
    if (e.key === 'Escape') clear();
    if (e.key === 'ArrowDown') focusNext();
    if (e.ctrlKey && e.key === 'k') openPalette();
    if (e.metaKey && e.key === 's') save();

    console.log(e.key);        // 'a', 'Enter', 'ArrowUp', etc.
    console.log(e.code);       // 'KeyA', 'Enter', 'ArrowUp' (layout-independent)
    console.log(e.keyCode);    // numeric code (legacy)
    console.log(e.shiftKey);   // boolean
    console.log(e.altKey);
    console.log(e.ctrlKey);
    console.log(e.metaKey);    // Cmd on Mac
  };
  return <input onKeyDown={handleKeyDown} />;
}

Form and Input Events

EventFires when
onChangeInput value changes (fires on every keystroke)
onInputNative input event (same as onChange in React)
onBlurInput loses focus
onFocusInput gains focus
onSubmitForm submitted
onResetForm reset
onSelectText selection changes
function Form() {
  const [value, setValue] = useState('');

  return (
    <form
      onSubmit={e => { e.preventDefault(); submit(value); }}
      onReset={() => setValue('')}
    >
      <input
        value={value}
        onChange={e => setValue(e.target.value)}
        onFocus={() => console.log('focused')}
        onBlur={() => validate(value)}
      />
      <button type="submit">Submit</button>
      <button type="reset">Reset</button>
    </form>
  );
}

Focus Events

// onFocus / onBlur bubble in React (unlike native focusin/focusout)
// Use them on a container to track focus within the subtree

function Dropdown() {
  const [open, setOpen] = useState(false);

  return (
    <div
      onFocus={() => setOpen(true)}
      onBlur={e => {
        // relatedTarget = element receiving focus
        if (!e.currentTarget.contains(e.relatedTarget)) {
          setOpen(false); // focus left the container
        }
      }}
    >
      <button>Toggle</button>
      {open && <ul>...</ul>}
    </div>
  );
}

Clipboard Events

<input
  onCopy={e => { e.preventDefault(); /* custom copy */ }}
  onCut={e => { /* ... */ }}
  onPaste={e => {
    const text = e.clipboardData.getData('text/plain');
    // e.clipboardData.files for file pastes
  }}
/>

Drag and Drop Events

function DragTarget() {
  const [over, setOver] = useState(false);

  return (
    <div
      draggable
      onDragStart={e => e.dataTransfer.setData('text/plain', 'payload')}
      onDragOver={e => { e.preventDefault(); setOver(true); }}
      onDragLeave={() => setOver(false)}
      onDrop={e => {
        e.preventDefault();
        const data = e.dataTransfer.getData('text/plain');
        setOver(false);
      }}
      onDragEnd={() => setOver(false)}
      style={{ background: over ? '#eee' : '#fff' }}
    >
      Drop here
    </div>
  );
}

Touch Events (mobile)

<div
  onTouchStart={e => console.log(e.touches[0].clientX)}
  onTouchMove={e => { /* e.touches, e.changedTouches */ }}
  onTouchEnd={e => { /* e.changedTouches */ }}
  onTouchCancel={() => { /* cleanup */ }}
/>

Scroll and Wheel Events

// onScroll — fires on scrollable elements
<div style={{ overflow: 'auto' }} onScroll={e => setScrollY(e.target.scrollTop)}>
  ...
</div>

// onWheel — fires on mouse wheel
<div onWheel={e => { console.log(e.deltaY, e.deltaX, e.deltaMode); }} />

Media Events

EventFires when
onPlayPlayback starts
onPausePlayback paused
onEndedPlayback ends
onTimeUpdatecurrentTime changes
onVolumeChangeVolume or mute changes
onLoadedDataMedia data loaded
onErrorLoad error
<video
  onPlay={() => setPlaying(true)}
  onPause={() => setPlaying(false)}
  onTimeUpdate={e => setTime(e.target.currentTime)}
  onError={e => setError('Failed to load')}
/>

Event Pooling (historical note)

React 16 and below pooled SyntheticEvents — properties were nullified after the handler returned. React 17+ removed pooling; you can safely access event properties asynchronously without e.persist().

// React 17+ — fine to use asynchronously
const handleChange = (e) => {
  setTimeout(() => console.log(e.target.value), 100); // works in React 17+
};

stopPropagation vs preventDefault

// preventDefault — stop browser default action (navigate, submit, etc.)
<a onClick={e => { e.preventDefault(); navigate('/about'); }}>About</a>

// stopPropagation — stop event from bubbling up to parent listeners
<div onClick={() => console.log('parent')}>
  <button onClick={e => { e.stopPropagation(); /* parent won't fire */ }}>
    Click
  </button>
</div>

// stopImmediatePropagation — also stop other listeners on the same element
<button onClick={e => { e.nativeEvent.stopImmediatePropagation(); }}>Click</button>

Capture Phase

Add Capture suffix to listen during the capture phase (top-down) instead of bubbling (bottom-up).

<div onClickCapture={() => console.log('fires first')}>
  <button onClick={() => console.log('fires second')}>Click</button>
</div>

Attaching Listeners Outside React (window/document)

Use useEffect for non-React event targets.

useEffect(() => {
  const handler = (e) => {
    if (e.key === 'Escape') closeModal();
  };
  document.addEventListener('keydown', handler);
  return () => document.removeEventListener('keydown', handler);
}, [closeModal]);