Build and apply custom cursors using CSS and images

Custom cursors let you tailor the user experience with visual cues that match your brand or creative goals. Whether it’s a hand-drawn icon, a game-like pointer, or just a fun twist on the default arrow, creating a custom cursor with CSS is easier than it sounds. This guide shows you how to do it step by step.
Key Takeaways
- Learn how to apply built-in cursors and custom image cursors
- Understand browser support, file formats, and sizing
- Avoid common issues with fallback and usability
Basic syntax of the CSS cursor
property
CSS provides a variety of built-in cursor types. Here’s how to use them:
.default {
cursor: default;
}
.pointer {
cursor: pointer;
}
.text {
cursor: text;
}
.help {
cursor: help;
}
.progress {
cursor: progress;
}
These built-in options cover standard interactions. But to go beyond, you can use your own image.
Creating a custom cursor from an image
To use an image as a cursor, you can pass a URL to the cursor
property.
Example:
.custom-cursor {
cursor: url('cursor.png') 4 4, auto;
}
url('cursor.png')
is your custom image4 4
is the hotspot (where the click is registered)auto
is the fallback cursor if the image fails to load
Supported formats
.cur
and.ico
(work best on Windows and Edge).png
(works widely, but may ignore hotspots in some browsers).svg
(less supported for cursors)
Recommended size
- Stick to 32x32 pixels or smaller for consistent behavior
- Images larger than 128x128 might be ignored or scaled down inconsistently
Cursor on hover only
To show a custom cursor only when hovering over specific elements:
.button:hover {
cursor: url('hover-cursor.png'), pointer;
}
This keeps the default cursor elsewhere and customizes interaction feedback.
Cursor alignment and compatibility tips
- Hotspot values are crucial — they define the active point of the cursor.
- Fallbacks ensure graceful degradation.
- Testing across Chrome, Firefox, Safari, and Edge is essential.
.cursor-test {
cursor: url('cursor.png') 16 0, auto;
}
Use tools like browser devtools or image editors to determine proper hotspot coordinates.
Extra tip: Avoid blurry cursors
Some browsers scale PNG cursors if they are not pixel-perfect. To prevent blurry rendering:
- Use exact 1:1 resolution (e.g., 32x32)
- Avoid transparent padding in your cursor images
Custom animated cursors (optional)
Animated cursors aren’t natively supported, but there are two common workarounds:
1. Use a GIF
.cursor-gif {
cursor: url('animated-cursor.gif'), auto;
}
- Works in some browsers, but not consistent.
- GIF may flicker or be ignored.
2. Use JavaScript to track mouse
const cursor = document.querySelector('.cursor');
document.addEventListener('mousemove', e => {
cursor.style.left = e.pageX + 'px';
cursor.style.top = e.pageY + 'px';
});
Then style the .cursor
div:
.cursor {
position: fixed;
pointer-events: none;
width: 32px;
height: 32px;
background-image: url('custom.png');
background-size: cover;
z-index: 9999;
}
Use cases for animated cursors
- Games and playful interfaces
- Custom creative websites or portfolios
Accessibility and UX considerations
Custom cursors should enhance — not hinder — usability. Keep in mind:
- Avoid replacing cursors on inputs and links unless it adds clarity
- Ensure visual designs don’t interfere with expected pointer behavior
- Use clear hotspots to prevent click mismatch
Best practices
- Test with keyboard and screen reader users
- Keep cursors visually distinct and lightweight
- Avoid applying cursors globally (e.g., to
body
) unless it makes sense contextually
Common pitfalls and debugging
Cursor not showing?
- Confirm image path is correct
- Use supported formats and dimensions
- Add a fallback:
cursor: url(...), auto;
Hotspot misaligned?
- Adjust the X and Y coordinates in the
cursor
value - Preview in an image editor to determine exact click point
Doesn’t work in Firefox or Safari?
- Try using
.cur
or.ico
instead of.png
- Avoid SVG and animated formats for critical interactions
- Safari ignores some image cursor formats altogether
Applying to the wrong element
If your cursor is not visible, make sure the CSS is applied to the visible and interactive element. For example:
body {
cursor: url('cursor.png'), default;
}
Conclusion
Custom cursors can add polish and playfulness to your UI, but they come with browser quirks. Stick to well-supported formats, test across browsers, and always include a fallback to ensure usability. Use custom cursors selectively where they improve clarity or reinforce branding, and avoid overuse where they may confuse users.
FAQs
CUR and PNG are most reliable. ICO works on Windows. SVG and GIF may not be supported consistently.
Check the image path, size (preferably 32x32), and provide a fallback with 'auto'.
Yes. Use a hover pseudo-class to apply a custom cursor only when the user hovers over specific elements.
Not reliably. GIFs may work in some browsers. For consistent animation, use JavaScript to move a custom element.
Use images sized exactly to 32x32 pixels without transparent padding. Avoid scaling in CSS.