Browser-Only Custom Cursors with the CSS cursor Property

Use plain CSS to ship a pixel cursor to every visitor of your site, without asking them to install anything. Includes hotspot tuning and fallbacks. · 6 min read

You can ship a custom cursor to every visitor of your website without asking them to install anything. The CSS cursor property accepts a URL, an optional hotspot, and a fallback cursor — that is the whole API.

body { cursor: url('/cursors/pointer.png') 4 4, auto; }

Hotspot tuning

The two integers after the URL are the hotspot — the pixel inside the image that actually counts as the cursor’s tip. For a standard arrow pointing up-and-left, that is 0 0. For a crosshair it is the center: 16 16 on a 32-pixel image. Get this wrong and your buttons will appear to be off by a few pixels.

Per-element cursors

You almost never want a single cursor for the whole page. Use the cursor property on specific elements: .btn { cursor: url('/cursors/hand.png') 8 4, pointer; }. The fallback after the comma is required — older browsers and screen-readers will skip the URL.

SVG cursors

Modern browsers accept .svg as a cursor source. This is excellent for crisp pixel art if you mark up the SVG with shape-rendering="crispEdges" — the same trick CursorCraft uses to render its preview thumbnails on this very page.

Performance

Browsers cache cursor images aggressively, but the first hover after a navigation can briefly flash the fallback while the cursor PNG loads. Inline the cursor as a data URL for the most critical elements (buttons, links above the fold) to remove the flash.

Accessibility

Custom cursors interact poorly with high-contrast OS themes and pointer-magnification tools. Always provide a sensible fallback (pointer, text, crosshair) and never use a custom cursor as the sole indicator that an element is interactive.

More guides