Dot Cursor Follower
A small dot replaces the native cursor and tracks the pointer inside its panel.
3 frameworksBeginner
An inline SVG arrow replaces the cursor and leans into the direction of travel.
<!--
An inline SVG replaces the native cursor and tilts toward the direction of
travel. cursor:none is set by the script so the panel keeps a real cursor if
JS never runs; the tilt is decoration, so reduced motion skips the rotation
and the arrow simply follows.
-->
<div id="cursor-svg-stage" class="relative w-full max-w-lg overflow-hidden rounded-2xl border border-gray-200 bg-gray-50 dark:border-gray-800 dark:bg-gray-900">
<div class="flex h-56 items-center justify-center px-6 text-center">
<p class="text-sm text-gray-600 dark:text-gray-400">A custom SVG pointer that leans into your motion</p>
</div>
<div id="cursor-svg" class="pointer-events-none absolute left-0 top-0 opacity-0 transition-opacity duration-150" aria-hidden="true">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" class="drop-shadow">
<path d="M4 2 L20 12 L12 13 L9 21 Z" fill="#2563eb" stroke="#fff" stroke-width="1.5" stroke-linejoin="round" />
</svg>
</div>
</div>
<script>
(() => {
const stage = document.getElementById('cursor-svg-stage');
const cur = document.getElementById('cursor-svg');
if (!stage || !cur || !matchMedia('(pointer: fine)').matches) return;
const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
let rect = stage.getBoundingClientRect();
let lx = 0, ly = 0, angle = 0;
stage.style.cursor = 'none';
stage.addEventListener('pointerenter', (e) => {
rect = stage.getBoundingClientRect();
lx = e.clientX - rect.left; ly = e.clientY - rect.top; cur.style.opacity = '1';
});
stage.addEventListener('pointerleave', () => { cur.style.opacity = '0'; });
stage.addEventListener('pointermove', (e) => {
const x = e.clientX - rect.left, y = e.clientY - rect.top;
if (!reduce) {
const dx = x - lx, dy = y - ly;
if (dx * dx + dy * dy > 4) angle = Math.atan2(dy, dx) * 180 / Math.PI - 45;
}
cur.style.transform = 'translate3d(' + x + 'px,' + y + 'px,0) rotate(' + angle + 'deg)';
lx = x; ly = y;
});
})();
</script>| Prop | Type | Default | Description |
|---|---|---|---|
hint | string | 'A custom SVG pointer that leans into your motion' | Hint |
className | string | - | Additional classes merged onto the root element. |
Swap the inline `<path>` for any shape. The tilt derives from movement direction and ignores sub-pixel jitter; it is decoration, so `prefers-reduced-motion` keeps the arrow upright while it still follows.