Plugins

Custom Plugins

Learn how to build your own cursor.js plugins using the CursorPlugin interface.

Building Custom Plugins

cursor.js allows unlimited extensibility via a very simple and robust CursorPlugin interface.

By implementing specific lifecycle methods from the CursorPlugin interface, your code is executed automatically at each important phase of the Cursor's workflow.

The CursorPlugin Interface

export interface CursorPlugin {
  name: string;
  install: (cursor: Cursor) => void;
  // Lifecycle hooks
  onMoveStart?: (x: number, y: number) => void;
  onMove?: (x: number, y: number) => void;
  onClickStart?: (target: Element) => void;
  onHoverStart?: (target: Element) => void;
  onTypeStart?: (text: string) => void;
  onStateChange?: (newState: Record<string, any>, oldState: Record<string, any>) => void;
  onDestroy?: () => void;
}

Example: Log Clicks Plugin

Here's an example of how you can build a very basic custom plugin that listens for the onClickStart hook:

import { CursorPlugin, Cursor } from 'cursor.js';

class MyClickLoggerPlugin implements CursorPlugin {
  name = 'MyClickLogger';

  install(cursor: Cursor) {
    console.log('Plugin has been initialized and bound to the cursor');
  }

  onClickStart(target: Element) {
    console.info('Custom Plugin caught a click on:', target);
  }
}

Usage

const cursor = new Cursor();
cursor.use(new MyClickLoggerPlugin());
cursor.click('.any-element'); // Output: Custom Plugin caught a click on: [Element]

Asynchronous Limitations

When writing standard custom plugins, remember: Ensure all event handling within the plugin acts purely side-effect based, updating internal visual states without relying on blocking the main cursor queue with recursive wait() calls. Delay visual effects correctly by utilizing traditional SetTimeout, custom promises or CSS Transitions.

On this page