Custom CSS Mouse Pointers Using Inline SVG

Implementing custom mouse pointers using inline SVG in CSS provides a lightweight, scalable way to customize user interactions without relying on external image files. By converting SVG markup into a data URI directly within the CSS cursor property, developers can create sharp, resolution-independent pointers that support custom colors, shapes, and precise hotspot coordinates.

The Basic Syntax

To use an inline SVG as a cursor, define the SVG code inside a url() functional notation using a data:image/svg+xml URI scheme, followed by coordinates for the pointer’s hotspot and a mandatory fallback cursor:

.custom-cursor {
  cursor: url('data:image/svg+xml;utf8,<svg ...>...</svg>') x y, auto;
}

URL-Encoding the SVG

Raw SVG markup containing special characters such as #, <, >, and quotes must be URL-encoded (or formatted cleanly) to ensure cross-browser compatibility. Most importantly, hex colors using # must be replaced with %23.

Here is an example of an inline SVG crosshair pointer with a defined fill color and dimensions:

.target-area {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23ff0055' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='2' x2='12' y2='22'/%3E%3Cline x1='2' y1='12' x2='22' y2='12'/%3E%3C/svg%3E") 12 12, crosshair;
}

Base64 Encoding Alternative

Alternatively, the SVG can be converted to Base64 to avoid URL-encoding issues with complex SVG markup:

.custom-pointer {
  cursor: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij48Y2lyY2xlIGN4PSI4IiBjeT0iOCIgcj0iNiIgZmlsbD0iIzAwN2FmZiIvPjwvc3ZnPg==') 8 8, pointer;
}

Defining the Cursor Hotspot

The hotspot represents the exact pixel coordinate where the click event triggers relative to the top-left corner (0, 0) of the SVG canvas:

Best Practices and Limitations

  1. Always Include Fallbacks: Browsers require a generic CSS cursor (such as auto, default, or pointer) after the url() value. Omitting the fallback will cause the custom cursor rule to be ignored.
  2. Explicit Dimensions: Always define width and height attributes on the root <svg> element to ensure consistent rendering across different browsers.
  3. Size Constraints: Keep dimensions within typical cursor limits. Most operating systems and browsers cap cursor sizes at 32×32 or 128×128 pixels. Excessively large SVGs will either be cropped or ignored entirely.