Custom images

cursor: url() in CSS: custom image cursors that work

url() replaces the system cursor with your own image. You give it an image, an optional hotspot and a keyword to fall back on, and the browser does the rest.

cursor: url(studio-arrow-32.png); Move your mouse over this box Cursors only appear with a mouse or trackpad. Open this page on a computer to see this one.
A 32 × 32 PNG with its hotspot at 3 2, falling back to auto.

What it shows

Your image, at its natural size, with the hotspot where you put it. If the image fails to load, is larger than 128x128, or would stick out of the page area, the browser moves on to the next image in the list and finally to the keyword. A .cur file can carry its own hotspot; PNG and SVG use the coordinates you write, or the top-left corner.

Usage

When to use it

Use it for

  • Brand moments: a portfolio, a launch page or a game where the cursor is part of the look.
  • Tools that need a cursor the system does not have, such as a brush outline, an eyedropper or a sized eraser.
  • A higher-contrast version of a system cursor on a dark or busy background.
  • Keep the image at 32x32, offer an SVG or a 2x file for sharp screens, and always end the list with a keyword.

Avoid it for

  • Site-wide on content pages, where it mostly gets in the way of reading and clicking.
  • Large images. Above 128x128 every browser ignores them, and larger ones are dropped near the edges of the page.
  • Animation. Browsers show a single frame of a GIF, and .ani files do not work at all.

Code

Copy the snippet

CSS
.brand-zone {
  cursor: url("/demo/studio-arrow.svg") 3 2,
          url("/demo/studio-arrow-32.png") 3 2,
          auto;
}
HTML
<div class="brand-zone">
  Move over this box to see the custom arrow.
</div>

Support

Browsers and systems

Browser support for url()
BrowserSupport
Chrome1
Edge12
Firefox1.5
Safari3
Safari on iOSpartial: 13.4+, hotspot coordinates ignored
Chrome on Android18
The matching operating system cursor
SystemMatching cursor
Windows roleany role, via your own .cur or .ani file
Windows fileyour file
macOScustom image

Watch out

Gotchas

  • The keyword at the end is required. cursor: url(a.png); is invalid, and the browser ignores the whole declaration.
  • The hotspot is measured in image pixels from the top-left corner. Chrome and Firefox clamp a hotspot that falls outside the image; Safari ignores it and uses the file's own hotspot or 0 0. Leave it out and every browser uses the hotspot stored in a .cur file, or 0 0.
  • Chrome 156 and later, and Safari, drop any custom cursor that would stick out of the visible page. Firefox, and Chrome before 156, do this only for cursors larger than 32x32. Near the top edge or a scrollbar you then see the fallback.
  • Give an SVG cursor width and height attributes. Browsers only have to support SVG cursors that state their own size.
  • On iPad, hotspot coordinates are ignored.
  • Browsers show one frame of an animated image, and no current browser plays .ani files.

FAQ

Questions

What size should a custom cursor be?
32x32 pixels. It matches the system cursor, works in every browser and is not dropped near the edges of the page. 128x128 is the hard ceiling.
Why does my custom cursor not show?
The usual reasons: no fallback keyword (which makes the whole rule invalid), a wrong path, an image larger than 128x128, or a cursor that would stick out of the page near an edge. Check that the rule is not crossed out in developer tools, then try a 32x32 PNG.
Can I use an animated GIF as a cursor?
You can, but browsers show a single frame. For animation you need a JavaScript cursor that follows the pointer.