native-cursor
v1.1.8
Published
A lightweight Node.js native addon for controlling the Windows system cursor.
Maintainers
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-cursordoes 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-cursorThe 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:
nameis missing.nameis 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);
// 42Promises 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());
// nullAliases 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");
// falseParameters
| 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"); // workingAliases 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());
// nullError 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);
// TypeErrorcursor.with() also validates its callback:
cursor.with("busy");
// TypeErrorRequirements
- Windows
- Node.js with Node-API support
The addon uses Windows APIs including:
LoadCursorWSetSystemCursorSystemParametersInfoWCopyIconDestroyCursor
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.
