npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@holmesdev/cursors

v1.0.3

Published

React cursor component — fully customizable, accessibility-first, and SVG-based

Downloads

120

Readme

🖱️ @holmesdev/cursors

npm version npm downloads bundle size license TypeScript

Fully customizable mouse cursor component for React — SVG-based and accessibility-first.

📚 Contents

📖 Overview

@holmesdev/cursors lets you replace the default pointer with a beautiful, customizable, multi-layer cursor system for React — complete with prebuilt shapes, deep configuration options, and built-in accessibility.

Features

  • 🎨 Multi-layer support — stack any number of customizable layers to build complex cursor designs
  • 🧩 Built-in shapes — arrow, circle, crosshair, and square
  • 📝 Custom shapes — use any user-provided SVG of your choice as a cursor layer
  • ⚙️ Deep configuration — fine-grained control over size, color, behaviour, and more
  • ♿ Accessible by default — fully baked-in under the hood, including automatic safety fallbacks
  • 🔧 Fully declarative React API
  • 💻 TypeScript support — fully typed props and layers
  • 🪶 Lightweight & performant — optimized rendering with minimal overhead
  • 📦 Small bundle footprint — ideal for any modern React application
  • 🔓 Open-source (MIT) — freely available and fully open-source

🚀 Getting Started

Installation

npm install @holmesdev/cursors
# or
yarn add @holmesdev/cursors

Usage

import ReactCursor from "@holmesdev/cursors";

function App() {
  return (
    <>
      {/* Import component into your top-level component */}
      <ReactCursor />

      <h1>Hover around the page!</h1>
    </>
  );
}

export default App;

🛠️ Configuration

Options for a React Cursor are divided into 2 types:

  • global - applies to the entire cursor component, or
  • layer - applies to each individual layer separately.

Global Options

Global options are passed directly to the component through props, and apply to the entire component. For example:

<ReactCursor enable={false} />

| Prop | Type | Default | Description | | ---------------------- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | enable? | boolean | true | Enables or disables the cursor entirely. | | showSystemCursor? | boolean | true | Shows or hides the system cursor. | | layers? | CursorLayer[] (refer to Layer Options) | [{ fill: "black", stroke: "white", strokeSize: 10, size: { width: 20, height: 20 } }] | Defines each cursor layer. | | mixBlendMode? | CSSProperties["mixBlendMode"] | "normal" | Controls how the cursor blends with the background. | | zIndex? | number | 2147483647 | Cursor z-index. Default is max value. | | ignoreAccessibility? | boolean | false | Bypass system accessibility detection. By default, if a user has any accessibility flags set in their browser, the custom cursor will disable and the system cursor will show instead. | | hoverSelector? | string | "a, button, [role='button'], input, textarea, select" | CSS selector that triggers hover effects. |

Layer Options

React Cursors have one or more layers with their own set of options. For example:

<ReactCursor
  layers={[
    {
      // Layer options here... e.g.
      SVG: "circle",
    },
  ]}
/>

| Prop | Type | Default | Description | | ---------------------- | -------------------------------------------------------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SVG? | SvgDefaultStyles | FC<SVGProps<SVGSVGElement>> | "circle" | Defines which SVG image to use for the cursor layer. SvgDefaultStyles include: "circle", "cross", "square", "arrow". To supply your own SVG, you must first convert it to a React Functional Component. See more here | | fill? | string | "black" | Replaces the fill=currentColor within layer's SVG file. Can supply any valid CSS color, such as "black", "#000", "rgb(0,0,0)", etc. | | stroke? | string | "white" | Replaces the stroke=currentStroke within layer's SVG file. | | strokeSize? | number | 10 | Adjusts the stroke size of the layer's SVG. | | opacity? | number | 1 | Adjust the opacity of the layer. | | size? | { height: number, width: number } | { height: 25, width: 25 } | Adjust the px height/width of the SVG. Aspect-ratio is retained by default, so the smallest value will usually be used for the size. | | preserveAspectRatio? | boolean | true | Preserves the aspect-ratio of the SVG layer, regardless of the size attribute provided. If false, the SVG will stretch/scale exactly as specified by the size attribute. | | delay? | number | 0 | The amount of "lag" that the layer will have, with respect to the actual system cursor position. Higher number = greater lag. | | effects? | CursorEffects (refer to Cursor Effects) | undefined | Defines hover and click effect states. | | hotspot? | { x: number, y: number } | { x: width/2, y: height/2 } | X/Y coordinate override for where the actual "click" hotspot of the cursor layer is. By default, the click is centered within the SVG image. If top-left is required, for example when using an "arrow" style SVG, the hotspot should be set at x=0 & y=0. |

✨ Cursor Effects

Cursor effects allow you to dynamically change the cursor's appearance when users interact with certain elements. Effects are applied per-layer.

Effect Types

  • hover - Triggered when the mouse hovers over interactive elements (defined by hoverSelector)
  • click - Triggered when the user presses down the mouse button (released on mouse up)

*Note: click effects take precedence over hover effects when both are active.*

Effect Properties

Each effect (hover or click) accepts the following properties:

| Prop | Type | Description | | ------------- | --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | SVG? | SvgDefaultStyles | FC<SVGProps<SVGSVGElement>> | Changes the SVG shape during the effect. Can use built-in shapes ("circle", "cross", "square", "arrow") or custom SVG component. | | fill? | string | Changes the fill color during the effect. | | stroke? | string | Changes the stroke color during the effect. | | strokeSize? | number | Changes the stroke size during the effect. | | opacity? | number | Changes the opacity (0-1) during the effect. | | scale? | number | Scales the cursor size (1 = normal, 2 = double size, 0.5 = half size). Multiplies the layer's base size. | | hotspot? | { x: number, y: number } | Overrides the X/Y coordinates for the SVGs click location. This is useful when changing to an SVG that uses a different click point (e.g. changing from "circle" to "arrow"). |

Customizing Hover Targets

By default, hover effects trigger on interactive elements: "a, button, [role='button'], input, textarea, select". You can customize this with the hoverSelector prop:

<ReactCursor
  hoverSelector=".custom-hover, [data-interactive]" // Custom CSS selector
/>

🖼️ Custom SVGs

The cursor component comes with preset SVGs like "circle", "cross", "square", and "arrow".

If you want to use a custom SVG, that is also supported. However, the ReactCursor component does not accept raw SVG files/strings directly. Instead, the SVG must first be converted into a React Functional Component. These are the recommended methods:

  • METHOD ONE: The easiest method is to copy/paste your SVG code directly into the online SVGR playground. This will output a JSX component that you can use directly.

    1. Copy/paste your .svg code into the input section.
    2. Copy/paste the output into a new JSX file (e.g. MyCustomSVG.jsx).
    3. Import the SVG Component within your application.
  • METHOD TWO: Alternatively, you can automonize this conversion within your application by using React SVGR within your project. For instance, with Vite:

    1. Install the dependency.
    npm install --save-dev vite-plugin-svgr
    1. Configure the plugin.
    // vite.config.js
    plugins: [ svgr() ],
    1. Import the SVG normally.

Importing Custom SVGs

import MyCustomSVG from "/path/to/file.jsx"; // for manually created SVG component (i.e. METHOD ONE)
import MyCustomSVG from "/path/to/file.svg"; // for react-svgr (i.e. METHOD TWO)

export default function Example() {
  return (
    <ReactCursor layers={[
      {
        SVG: MyCustomSVG, // can now fully-customize your SVG through the cursor component
        fill: "red",
        stroke: "blue",
      }
    ]}>
  );
}

NOTE

To make your SVG fully customizable, avoid hard-coding values. Hard-coded values will always take precedence over the cursor component’s props.

For example, within your actual .svg file:

  • Height and Width: Omit these in the SVG. The cursor component’s size prop will control the dimensions.
  • Colors: Use fill="currentColor" and stroke="currentStroke" for dynamic colors. This allows the cursor component’s fill and stroke props to control the appearance.
    • ⚠️ If you hard-code colors like fill="red", the SVG will always display in red, ignoring the component’s props.

📝 Examples

  • Multiple examples have been pre-made and can found here
  • These example can be viewed in realtime by accessing the examples section of our website
  • Alternatively, you can demo the cursor configuration by accessing our live demo testbed.

🧠 Accessibility

By default, the component respects user system preferences and disables itself when:

  • Reduced motion is requested
  • High contrast or forced colors mode is active
  • Coarse pointer (touch) is detected

You can override this by setting ignoreAccessibility={true}.

Refer to ACCESSIBILITY for more details.

ℹ️ About Haus of Cards

Haus of Cards is a student team who created the React Cursor project at Holmesglen Institute of TAFE in 2025 as part of their course.

🤝 Contributing

Refer to CONTRIBUTING for guidelines. Please also review our CODE OF CONDUCT.

🧾 License

MIT © 2025 (refer to LICENSE).