Framework-agnostic · Zero dependencies · TypeScript

The cursor that knows what it's doing

Your cursor transforms dynamically — play on video, sliders on carousels, exit arrow on external links. One line of code. Works everywhere.

⚡ ~5.6 KB gzip 0 deps React · Vue · Vanilla · CDN

Live demo

Hover each card to see the cursor transform in real-time. Switch between themes to see different visual styles.

Hover to see play/pause cursor

play pause Detected from <video>
◀───●───▶

Hover over the slider

slider Detected from input[type=range]
external-link pointer Different vs. same origin
text Detected from <input>, <textarea>
aria-disabled
disabled Highest priority detection
[role=button]
pointer <button>, role=button, <select>
🖼 Hover me → zoom-in
⊕ Hover me → drag
⟳ Hover me → loading
⊘ Hover me → disabled
custom rule Via cursorRules option
✦ Drag me
drag Detected from draggable="true"
📋 copy
❓ help
↔ resize-h
↕ resize-v
↗ external-link
⏺ record
new Custom cursors via data-cursor
Current cursor: default

Install & use

npm install cursor-as-tool
import { CursorAsTool } from 'cursor-as-tool';

const cursor = new CursorAsTool({
  smooth: true,
  smoothSpeed: 0.12,
  theme: 'gaming',  // 'minimal' (default) or 'gaming'
  cursorRules: [
    { selector: '.gallery img', cursorType: 'zoom-in' },
  ],
});

cursor.init();

// Clean up when done:
cursor.destroy();
import { useCursorAsTool } from 'cursor-as-tool/react';

function App() {
  // init on mount, destroy on unmount — automatic
  useCursorAsTool({ smooth: true, theme: 'gaming' });

  return <main>Your app</main>;
}
<script src="https://unpkg.com/cursor-as-tool/dist/cursor-as-tool.umd.global.js"></script>
<script>
  // One-liner (uses minimal theme by default)
  CursorAsTool.init();

  // Or with gaming theme
  const c = new CursorAsTool.CursorAsTool({ smooth: true, theme: 'gaming' });
  c.init();
</script>

API reference

Config options

OptionTypeDefault
hideNativeCursorbooleantrue
sizenumber32
zIndexnumber9999
smoothbooleanfalse
smoothSpeed0–10.15
cursorRulesCursorRule[][]
containerHTMLElementdocument.body
theme'minimal' | 'gaming''minimal'

Cursor types

defaultpointertextcopyhelpresize-hresize-vexternal-linkrecordplaypausesliderdraggrabbingzoom-inzoom-outdisabledloading

data-cursor attribute

Set any cursor type directly in HTML — no JavaScript needed:

<div data-cursor="zoom-in">Gallery item</div>
<div data-cursor="loading">Async content</div>