Making a custom interactive cursor using plain HTML, CSS3 and Javascript

Custom is better controlled

In my 5 years of working as a web developer and collaborating with designers, I've never had a single design where we've considered using the cursor for a better interactive experience. That's partly because custom cursors go against the existing mental model that an average user, or a designer has about cursors, and a primary rule of design to use existing mental models to reduce the cognitive load on the user. Also, the list of cursor options provided by default are very powerful can be helpful in sharing meta information about the DOM element, Refer to MDN for a list of existing css setting for the cursor. However, one can always go against the pattern if a greater purpose is solved. The users will always get used to the new mental model if they find it useful. That said, cursors are easily overlooked as a design component.

Denis Rouve's portrait gallery is an awesome example for a smartly used custom cursor.

An awesome use of a custom cursor
An awesome use of a custom cursor

Another awesome custom cursor
Another awesome custom cursor

What makes up a custom cursor?

While all OS support some informatory cursor types, and the basic use of an image as a cursor, that sets the extent of customizations that are natively supported. Native options cannot be animated and do not support any animations on click, hover or related events.

.custom-cursor { width: 200px; height: 200px; cursor: url(, auto;}

Even though the specification does not limit the size of the cursor image used, browsers agents commonly set limits to prevent misuse. Chromium and Firefox have a limit of 32px x 32px.

For any custom interactivity with cursors, you's need a mix of Javascript with CSS, or the HTML canvas element if you're willing to go creative. To make a custom cursor, one would have to -

  • Hide the existing cursor
  • Make your own HTML element that would follow the invisible cursor using transform.
  • Handle pointer events on the DOM element

The first part of the problem is also the easiest one. Setting the cursor to none would do the trick.

* { cursor: none;}

Following the invisible cursor with a DOM element

<container_dom_element>.onmousemove =function (e) { = `translate(${e.nativeEvent.clientX}px, ${e.nativeEvent.clientY}px)`;}

With Javascript comes the flexibility to mutate styles for any dom element on the fly. Wanna make a cat chase your cursor on the screen? That's possible now.

Handling the cursor events on the DOM element

There might be few cases in which one would one to handle all the events on the custom cursor, allowing some and rejecting the others. However, in most cases, you would want to use

.custom-cursor { pointer-events: none;}

That's it folks!

Hope this was helpful! Feel free to share your insights on the blog from the Contact Page, or by directly dropping an email If you have anything that would help improve this setup, I'd love to hear and discuss about it.