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 🙏

© 2026 – Pkg Stats / Ryan Hefner

native-cursor

v1.1.8

Published

A lightweight Node.js native addon for controlling the Windows system cursor.

Readme

Native Cursor

A lightweight Node.js native addon for controlling the Windows system cursor.

Built with C++, Node-API (N-API), and the Windows Win32 cursor APIs.

[!WARNING] This changes the Windows cursor system-wide.

native-cursor does not only affect your Node.js application. Other applications running on Windows may also be affected.

Use cursor.with() when you want a temporary cursor change that is automatically restored.

  • Platform: Windows only (x64 and ARM64)
  • Implementation: C++ / Node-API

Installation

npm install native-cursor

The package uses a native Windows addon and requires a compatible prebuilt binary for your platform and architecture.


Quick Start

const cursor = require("native-cursor");

cursor.set("busy");

// ... do something ...

cursor.restore();

For temporary changes, .with() is usually the better option:

await cursor.with("busy", async () => {
  await doSomething();
});

The cursor is automatically restored when the callback finishes — even if it throws an error.


API

cursor.set(name)

Changes all supported Windows system cursor roles to the cursor represented by name.

cursor.set("pointer");

This is a system-wide operation. It is not limited to the current Node.js process or application.

Parameters

| Parameter | Type | Description | | --------- | -------- | ------------------------------- | | name | string | Cursor name or supported alias. |

Example

cursor.set("busy");

All supported cursor roles will use the Windows busy/wait cursor.

Errors

Throws when:

  • name is missing.
  • name is not a string.
  • The cursor name is unknown.
  • Windows cannot restore the existing cursor configuration.
  • Windows cannot load the requested cursor.
  • Windows cannot replace one of the system cursor roles.
try {
  cursor.set("does-not-exist");
} catch (error) {
  console.error(error.message);
}

cursor.restore()

Restores the Windows system cursors to their configured/default state.

cursor.restore();

Internally, this uses the Windows:

SystemParametersInfoW(SPI_SETCURSORS)

After a successful restore, cursor.current() returns null.

Returns

undefined

Example

cursor.set("pointer");

// ... application work ...

cursor.restore();

Errors

Throws if Windows cannot restore the cursor configuration.

try {
  cursor.restore();
} catch (error) {
  console.error(error.message);
}

cursor.with(name, callback)

Temporarily changes the system cursor while a callback runs, then automatically restores the previous cursor state.

This is the recommended API for temporary cursor changes.

Synchronous

cursor.with("busy", () => {
  doSomethingSync();
});

Asynchronous

await cursor.with("busy", async () => {
  await doSomethingAsync();
});

The cursor remains active for the entire asynchronous operation.

Errors are handled automatically

try {
  await cursor.with("busy", async () => {
    await doSomething();
    throw new Error("Something went wrong");
  });
} catch (error) {
  console.error(error.message);
}

Even though the callback throws, the cursor is restored before the error is propagated.

Return values

The callback's return value is passed through:

const result = cursor.with("pointer", () => {
  return 42;
});

console.log(result);
// 42

Promises are also passed through:

const result = await cursor.with("busy", async () => {
  return "done";
});

console.log(result);
// "done"

Recommended usage

Instead of:

try {
  cursor.set("busy");

  await doSomething();
} finally {
  cursor.restore();
}

you can write:

await cursor.with("busy", async () => {
  await doSomething();
});

This makes temporary cursor changes easier to manage and much harder to forget to restore.


cursor.current()

Returns the cursor most recently applied by this library.

console.log(cursor.current());

Returns

| Value | Meaning | | -------- | ---------------------------------------------------------- | | string | The canonical cursor name most recently set by the library | | null | The library has not currently set a cursor |

Example:

console.log(cursor.current());
// null

cursor.set("hand");

console.log(cursor.current());
// "pointer"

cursor.restore();

console.log(cursor.current());
// null

Aliases are returned as their canonical names:

cursor.set("hand");

cursor.current();
// "pointer"

Important

current() does not query the actual Windows cursor configuration.

It tracks the cursor state managed by native-cursor.

For example, if another application changes the Windows cursor configuration after:

cursor.set("busy");

cursor.current() may still return:

"busy"

because that is the last cursor this library applied.


cursor.list()

Returns all canonical cursor names supported by the addon.

console.log(cursor.list());
[
  "normal",
  "text",
  "busy",
  "crosshair",
  "up",
  "resize-diagonal",
  "resize-diagonal-2",
  "resize-horizontal",
  "resize-vertical",
  "resize-all",
  "not-allowed",
  "pointer",
  "working"
]

These are the canonical names accepted by cursor.set().


cursor.isSupported(name)

Checks whether a cursor name or alias is supported.

cursor.isSupported("pointer");
// true

cursor.isSupported("hand");
// true

cursor.isSupported("banana");
// false

Parameters

| Parameter | Type | Description | | --------- | -------- | --------------------- | | name | string | Cursor name or alias. |

Returns

boolean

Returns true if the name is recognized.

Throws a TypeError if name is not a string.


Supported Cursors

| Name | Aliases | Windows cursor | | ------------------- | ------------------ | ---------------------------- | | normal | default, arrow | Standard arrow | | text | ibeam | Text / I-beam | | busy | wait | Wait / busy | | crosshair | cross | Crosshair | | pointer | hand | Hand / pointer | | not-allowed | no | Not allowed | | working | app-starting | Application starting | | up | — | Up arrow | | resize-diagonal | — | Northwest / southeast resize | | resize-diagonal-2 | — | Northeast / southwest resize | | resize-horizontal | — | Horizontal resize | | resize-vertical | — | Vertical resize | | resize-all | — | Four-direction resize |


Aliases

Aliases are accepted by both cursor.set() and cursor.isSupported().

cursor.set("default");      // normal
cursor.set("arrow");        // normal

cursor.set("ibeam");        // text

cursor.set("wait");         // busy

cursor.set("cross");        // crosshair

cursor.set("hand");         // pointer

cursor.set("no");           // not-allowed

cursor.set("app-starting"); // working

Aliases are normalized when reported by cursor.current().

For example:

cursor.set("hand");

cursor.current();
// "pointer"

System-wide Behavior

native-cursor modifies the Windows system cursor configuration.

For example:

cursor.set("crosshair");

does not simply change the cursor inside your Node.js application.

It replaces the supported Windows system cursor roles, which means other applications may also display the changed cursor.

Always clean up

For long-running changes:

cursor.set("pointer");

// ... application work ...

cursor.restore();

For temporary changes, prefer:

await cursor.with("pointer", async () => {
  await doSomething();
});

Failure Recovery

When applying a cursor, the addon first restores the Windows cursor configuration and then applies the requested cursor to the supported cursor roles.

If applying the new cursor fails partway through, the addon attempts to restore the Windows cursor configuration before throwing the error.

You should still use cursor.restore() or cursor.with() when appropriate so your application's lifecycle is explicit.


Examples

Temporary busy cursor

const cursor = require("native-cursor");

async function doWork() {
  await cursor.with("busy", async () => {
    await performWork();
  });
}

doWork();

Synchronous operation

cursor.with("crosshair", () => {
  performSynchronousOperation();
});

Nested cursor changes

await cursor.with("busy", async () => {
  await doSomething();

  await cursor.with("pointer", async () => {
    await doSomethingElse();
  });

  // Returns to the previous library-managed cursor state.
});

Manual control

cursor.set("pointer");

console.log(cursor.current());
// "pointer"

doSomething();

cursor.restore();

console.log(cursor.current());
// null

Error Handling

Native Windows errors are exposed as JavaScript Error objects containing the relevant Win32 error code.

try {
  cursor.set("invalid-cursor");
} catch (error) {
  console.error("Cursor error:", error.message);
}

Invalid arguments result in TypeError exceptions:

cursor.set();
// TypeError

cursor.set(123);
// TypeError

cursor.isSupported(123);
// TypeError

cursor.with() also validates its callback:

cursor.with("busy");
// TypeError

Requirements

  • Windows
  • Node.js with Node-API support

The addon uses Windows APIs including:

  • LoadCursorW
  • SetSystemCursor
  • SystemParametersInfoW
  • CopyIcon
  • DestroyCursor

Because it relies on Win32 APIs, Native Cursor is Windows-only.


API at a Glance

const cursor = require("native-cursor");

// Change the system cursor
cursor.set("busy");

// Check the library-managed cursor
cursor.current();

// Check supported cursors
cursor.list();

// Check a name
cursor.isSupported("pointer");

// Restore Windows cursors
cursor.restore();

// Temporary synchronous change
cursor.with("busy", () => {
  doSomethingSync();
});

// Temporary asynchronous change
await cursor.with("busy", async () => {
  await doSomethingAsync();
});

License

This project is licensed under the MIT License.