Using CSS cursors and how to customize them

- 👤 Andrés Cruz

🇪🇸 En español

Using CSS cursors and how to customize them

Changing the cursor with CSS is one of those small things that, when you discover them, you wonder how you weren't using them before.

It happened to me: I wanted to improve the experience on a rather minimalist interface and started testing different cursors. That's when I learned two things:

  1. Not all browsers load the same cursors,
  2. A poorly chosen cursor can ruin the user experience.

In this guide, I'm going to teach you everything I've learned using cursors with CSS: how they work, which ones exist, how to create your own, which errors to avoid, and how to use them without breaking usability.

What the cursor property is and what it's for

The cursor property defines the appearance of the pointer when the user hovers over an element. It's simple: you change the value and the cursor changes its look.

When you hover over a "text" input, the famous editing I-beam appears. Over a link, the small hand appears. All of this is controlled by the browser based on the element type... but you can override it.

How it works and when it is applied

The browser decides the default cursor, but you can change it on any element:

button { cursor: pointer; }

Does it have hover? Is it clickable? Be very careful: changing the cursor purely for aesthetics can confuse the user. I did it at first and ended up reverting because users didn't understand what they could click and what they couldn't.

Common errors when using cursors (and how to avoid them)

  • Using cursors that do not represent real actions
  • Setting enormous custom cursors (it feels slow and clumsy)
  • Not including a fallback when the browser does not support the image
  • Changing the cursor on touch screens (they don't exist there!)

With the cursor property that we will see next, we can change the appearance of the cursor over certain elements on our website; normally when we visit a website our cursor takes the shape of an arrow; but this changes when we place it over certain elements, for example, a "text" type input; where it usually takes the form of text editing.

Cursors on the web with CSS

The use of custom cursors in a web application can improve the end user experience; in this post, we will see how to use the cursors provided by CSS and custom cursors.

To use pre-defined cursors, we must set the value to the CSS property we want; while with a custom cursor, we must use an image as the value, which will represent the cursor.

Basic syntax for cursors in CSS

With CSS, we can set the type of cursor to use using the following syntax:

/*where 'cursor' is the property and 'value' is the value*/ 
cursor: valor;

Basic example of cursor usage

Like everything in CSS, there is a property:

.texto-editable { cursor: text; }

Applying the cursor to specific elements

For example, we can change the cursor on specific HTML elements that we define and not globally across the entire website:

.card { cursor: pointer; } 
.borde { cursor: ew-resize; }

I like to test each cursor in several browsers because some, surprisingly, don't render certain types. It has happened to me especially with rare cursors like context-menu.

Complete list of CSS cursors (with description and utility)

Here we have some examples of cursors already defined by the operating system or the browser; some of them may not load, all depending on the operating system or browser you use, so be very careful when choosing one:

  • Cursor    Description
  • default    Standard arrow
  • pointer    Hand indicating click
  • text    I-beam for text
  • wait    Indicates you must wait
  • progress    Loading in the background
  • help    Help sign
  • crosshair    Precision cross
  • move    Movement in all directions

Cursors for resizing elements

  • Cursor    Function
  • e-resize    Resize to the right
  • w-resize    Left
  • n-resize    Up
  • s-resize    Down
  • ne-resize    Up right
  • nw-resize    Up left
  • se-resize    Down right
  • sw-resize    Down left
  • ns-resize    Vertical
  • ew-resize    Horizontal
  • col-resize    Columns
  • row-resize    Rows

Functional and warning cursors

  • Cursor    Usage
  • not-allowed    Blocked action
  • no-drop    Cannot drop
  • copy    Indicates copying
  • alias    Alias or alternative access
  • none    No cursor

Examples of use:

/*default cursors*/ 
.alias           { cursor: alias; }
.auto            { cursor: auto; }
.cell            { cursor: cell; }
.copy            { cursor: copy; }
.context-menu    { cursor: context-menu; }
.crosshair       { cursor: crosshair; }
.default         { cursor: default; }
.help            { cursor: help; }
.move            { cursor: move; }
.none            { cursor: none; }
.pointer         { cursor: pointer; }
.progress        { cursor: progress; }
.text            { cursor: text; }
.vertical-text   { cursor: vertical-text; }
.wait            { cursor: wait; }

.no-drop         { cursor: no-drop; }
.not-allowed     { cursor: not-allowed; }

.all-scroll      { cursor: all-scroll; }

.col-resize      { cursor: col-resize; }
.row-resize      { cursor: row-resize; }

.e-resize        { cursor: e-resize; }
.n-resize        { cursor: n-resize; }
.s-resize        { cursor: s-resize; }
.w-resize        { cursor: w-resize; }

.ns-resize       { cursor: ns-resize; }
.ew-resize       { cursor: ew-resize; }
.ne-resize       { cursor: ne-resize; }
.nw-resize       { cursor: nw-resize; }
.se-resize       { cursor: se-resize; }
.sw-resize       { cursor: sw-resize; }
.nesw-resize     { cursor: nesw-resize; }
.nwse-resize     { cursor: nwse-resize; }

You can see it in practice here:

Custom Cursors with CSS

To set our own (custom) cursors, we simply indicate the URL of the image that will represent our cursor; several URLs can be indicated so that CSS tries to load multiple images; if the first pointer image does not load (the cursor does not exist, for example) or is not supported by the browser, it moves to the next image; let's see an example:

/*custom cursors*/
.pointer-custom { 
  cursor: url(pointer-custom.gif),
  url(pointer-custom.png), pointer 
}

Using url() to load your own cursor

  • You can use PNG, GIF, CUR, or even SVG in modern browsers.
  • Some browsers ignore the first image if it does not meet certain dimensions or format. So I always use several:
.cursor-custom {
  cursor: url("cursor.cur"), 
          url("cursor.png"), 
          pointer;
}

Fallbacks: how to ensure your cursor always works

  • First URL → ideal format
  • Second → alternative for rare browsers
  • Last → standard cursor

Using a fallback has saved me more than once, especially when a PNG didn't load in Safari.

Recommended formats (PNG, SVG, CUR)

  • CUR: optimal for Windows
  • PNG: good overall balance
  • SVG: super defined, but not all browsers support it well as a cursor

Sizes, optimization, and cursor quality

I learned this the hard way:

If the image is large, the cursor movement feels clumsy and slow.

Keep sizes at 24×24 or 32×32 pixels.

Good UX practices when choosing a cursor

  • When changing the cursor really improves the experience
    • Elements that are NOT native (clickable cards, interactive divs)
    • Drag and drop
    • Graphical elements, canvases, sliders
    • Highly visual interfaces
  • Cases where you should NOT change the cursor
    • If the user is accustomed to a standard cursor, do not change it.
    • Examples:
    • links → pointer 
      texttext 
      buttons → pointer
  • Cursors and touch screens (what no one tells you)
    • On mobile, there is no cursor, so don't use the cursor as an interaction indicator.
    • Better combine icons, shadows, or animations.

Accessibility and design: making cursors useful for everyone

What to expect based on the user's device:

  • mouse: precise interaction
  • trackpad: medium precision
  • touch: zero cursors
  • stylus: mixed behavior

Pointer Media Queries: pointer and any-pointer

@media (pointer: coarse) { 
  /* User uses finger → no cursors */ 
}

Difference between cursor and caret (caret-color)

The cursor follows the mouse.

The caret is the indicator where text is entered in inputs.

input { caret-color: red; }

Ready-to-copy examples: CSS cursors for your project

Buttons, links, and inputs:

.boton { cursor: pointer; }

Menus, sliders, and draggable elements

.drag { cursor: grab; } 
.drag:active { cursor: grabbing; }

Custom cursor with SVG

.custom-svg {
 cursor: url("cursor.svg") 0 0, pointer;
}

Frequently Asked Questions about CSS Cursors (FAQ)

  • Do cursors work on touch screens?
    • No. The cursor does not exist on touch screens.
  • Why doesn't my custom cursor appear?
    • It could be due to size, format, or lack of fallback.
  • What formats does CSS accept?
    • PNG, GIF, SVG (partial), CUR.
  • Can I put a different cursor on a div?
    • Yes, the cursor is applied by selector.
  • What size should a custom cursor be?
    • Ideally 24×24 or 32×32 px.

Conclusions

In conclusion, it is one more option we have to improve the visitor experience in our application; but always keep in mind that the cursor you choose should not be too different from the standards if you want your application to be easy to use.

CSS cursors are a simple yet powerful tool for guiding your users. That said, as I learned when I started experimenting, you have to use them wisely: good fallbacks, compatible formats, recognizable cursors, and always thinking about the real user experience.

If you choose the cursor well, your interface feels clearer, more intuitive, and more professional.

I agree to receive announcements of interest about this Blog.

Learn how to use and customize cursors with CSS. Discover all types of cursors, practical examples, custom cursors with images, fallbacks, ideal sizes, and UX best practices. A complete and easy-to-implement guide.

| 👤 Andrés Cruz

🇪🇸 En español