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

@signosoft/signpad-js

v0.4.7

Published

| Core Concepts & Overview | Getting Started & Usage | Advanced & Support | | :---------------------------------------- | :-------------------------------------------------- | :-----------------

Downloads

978

Readme

@signosoft/signpad-js

📍 Table of Contents

| Core Concepts & Overview | Getting Started & Usage | Advanced & Support | | :---------------------------------------- | :-------------------------------------------------- | :--------------------------------- | | 📜 Description | 📦 Installation | 💬 Feedback | | 🎬 Demo | 🔐 Licensing | 🛠️ Contributing | | ⚙️ Tech stack | 🚀 Quick Start | 📄 License | | | 📋 Properties | | | | 🧩 Methods | | | | 🎨 Styling | | | | 🌐 Localization | | | |

📜 Description

signosoft-signpad is a powerful and flexible web component built with LitElement, designed for seamless digital signature capture integration into modern web applications. It provides a unified interface for working with various signature devices like Wacom or Ugee, supporting both stylus and mouse-based signing.

This component works effortlessly with any modern stack: | JavaScript | React | Angular | Vue | |:-:|:-:|:-:|:-:| | | | | ||

It expertly handles the complexities of WebHID device connections, signature session lifecycles, and high-fidelity stroke rendering.

🎬 Demo

⚙️ Tech Stack / Built With

  • TypeScript
  • Lit
  • Vite

🔐 Lease Setup

To use the Signosoft Signpad component with physical signature hardware, a valid lease is required.

🛑 CRITICAL: Mandatory Initialization

Without a valid lease, the component can still render, but driver initialization and hardware communication features will be disabled.

1. Lease flow

  1. Generate/get your license key in Signosoft portal.
  2. Request a lease from the Signosoft lease API.
  3. Put the returned lease into config.lease.

Security note: In production, call the lease API from your backend and return only the lease to frontend.

2. Frontend implementation (plain JavaScript reference)

async function fetchLease() {
  try {
    const response = await fetch(
      "https://test.signosoft.com/api/v1/driver/leases",
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          licenceKey: "YOUR-LICENSE-KEY",
          validityHours: 24,
          port: 4204,
        }),
      },
    );

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(
        `License server error: ${response.statusText} - ${errorText}`,
      );
    }

    return await response.json();
  } catch (error) {
    console.error("Signosoft Signpad: License initialization failed", error);
    throw error;
  }
}

async function applyLeaseToConfig(currentConfig) {
  const lease = await fetchLease();
  return {
    ...currentConfig,
    lease,
  };
}

📦 Installation

Install the library via npm:

npm install @signosoft/signpad-js

Or using your preferred manager:

yarn add @signosoft/signpad-js
pnpm add @signosoft/signpad-js

🌍 Environment Requirements

To ensure proper communication via the WebHID API:

  • HTTPS: Required for all production environments (WebHID security policy).
  • Supported Browsers: Chrome 89+, Edge 89+, Opera (Chromium-based).
  • TypeScript: Built-in support; no extra @types needed.

🚀 Quick Start

First, install the core package:

npm install @signosoft/signpad-js

🧰 Framework Integration Guide

Angular Integration Guide

This guide describes how to integrate the @signosoft/signpad-js web component into an Angular application.

1. Installation

Install the core package using npm:

npm install @signosoft/signpad-js

2. Create the Bridge Directive

Since signosoft-signpad is a Web Component, Angular requires a Directive to properly sync configuration changes and provide typed access to the component instance.

Create signosoft-signpad.directive.ts:

import {
  Directive,
  ElementRef,
  Input,
  OnChanges,
  SimpleChanges,
} from "@angular/core";
import type { SignosoftSignpad, SignpadConfig } from "@signosoft/signpad-js";

@Directive({
  selector: "signosoft-signpad",
  standalone: true,
})
export class SignosoftSignpadDirective implements OnChanges {
  @Input() config?: SignpadConfig;

  constructor(private host: ElementRef<SignosoftSignpad>) {}

  // Access the native Web Component instance
  get signpadRef(): SignosoftSignpad {
    return this.host.nativeElement;
  }

  ngOnChanges(changes: SimpleChanges) {
    const el = this.host.nativeElement as any;
    for (const key of Object.keys(changes)) {
      el[key] = (this as any)[key];
    }
  }
}

3. Implementation in Component

Import the library, the directive, and add the CUSTOM_ELEMENTS_SCHEMA.

import {
  Component,
  ViewChild,
  CUSTOM_ELEMENTS_SCHEMA,
  AfterViewInit,
  signal,
} from "@angular/core";
import "@signosoft/signpad-js"; // Import the Web Component registration
import {
  type SignosoftSignpad,
  type SignpadConfig,
} from "@signosoft/signpad-js";
import { SignosoftSignpadDirective } from "./directives/signosoft-signpad.directive";

@Component({
  selector: "app-root",
  standalone: true,
  imports: [SignosoftSignpadDirective],
  templateUrl: "./app.component.html",
  schemas: [CUSTOM_ELEMENTS_SCHEMA], // Mandatory for custom HTML tags
})
export class AppComponent implements AfterViewInit {
  @ViewChild(SignosoftSignpadDirective)
  signpadDirective!: SignosoftSignpadDirective;

  public config = signal<SignpadConfig>({
    lease: undefined,
  });

  async ngAfterViewInit() {
    await this.applyLeaseToConfig();
  }

  public async fetchLease(): Promise<any> {
    try {
      const response = await fetch(
        "https://test.signosoft.com/api/v1/driver/leases",
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            licenceKey: "YOUR-LICENSE-KEY",
            validityHours: 24,
            port: 4204,
          }),
        },
      );

      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(
          `License server error: ${response.statusText} - ${errorText}`,
        );
      }

      return await response.json();
    } catch (error) {
      console.error("Signosoft Signpad: License initialization failed", error);
      throw error;
    }
  }

  public async applyLeaseToConfig() {
    const lease = await this.fetchLease();
    this.config.update((currentConfig) => ({
      ...currentConfig,
      lease,
    }));
  }

  // Helper to access methods easily (ok, clear, cancel, etc.)
  public get signpad(): SignosoftSignpad | undefined {
    return this.signpadDirective?.signpadRef;
  }
}

4. Component Template

Use the custom tag in your HTML and bind the configuration object.

<div>
  <div>
    <signosoft-signpad [config]="config()"></signosoft-signpad>
  </div>
</div>

React - Quick start

This guide describes how to integrate the @signosoft/signpad-js web component into a React application (Functional Components with Hooks).

1. Installation

Install the core package using npm:

npm install @signosoft/signpad-js

2. Implementation

In React, we use useRef for methods and useEffect to fetch a lease before updating config.

import { useEffect, useRef, useState } from "react";
import "@signosoft/signpad-js"; // Registers the web component
import type { SignpadConfig } from "@signosoft/signpad-js";

async function fetchLease() {
  try {
    const response = await fetch(
      "https://test.signosoft.com/api/v1/driver/leases",
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          licenceKey: "YOUR-LICENSE-KEY",
          validityHours: 24,
          port: 4204,
        }),
      },
    );

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(
        `License server error: ${response.statusText} - ${errorText}`,
      );
    }

    return await response.json();
  } catch (error) {
    console.error("Signosoft Signpad: License initialization failed", error);
    throw error;
  }
}

function App() {
  // Use ref to access component methods (ok, clear, connect, etc. by signpadRef.current)
  const signpadRef = useRef<any>(null);
  const [config, setConfig] = useState<SignpadConfig>({ lease: undefined });

  useEffect(() => {
    fetchLease().then((lease) => setConfig((prev) => ({ ...prev, lease })));
  }, []);

  return (
    <div>
      <h1>Signosoft Signpad React Example</h1>
      <signosoft-signpad ref={signpadRef} config={config} />
    </div>
  );
}

export default App;

Vue.js Integration Guide

This guide describes how to integrate the @signosoft/signpad-js web component into a Vue 3 application using the Composition API (<script setup>).

1. Installation

Install the core package using npm:

npm install @signosoft/signpad-js

2. Configure Vue to recognize Custom Elements

By default, Vue will try to resolve signosoft-signpad as a Vue component and will throw a warning. You need to tell Vue to ignore this tag.

If you are using Vite (vite.config.ts):

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
  plugins: [
    vue({
      template: {
        compilerOptions: {
          // Treat all tags starting with 'signosoft-' as custom elements
          isCustomElement: (tag) => tag.startsWith("signosoft-"),
        },
      },
    }),
  ],
});

3. Implementation

In Vue 3, we use ref for both the element and config, then fetch the lease and assign it to config.

<script setup lang="ts">
import { ref } from "vue";
import "@signosoft/signpad-js"; // Registers the Web Component
import type { SignpadConfig, SignosoftSignpad, IPenData } from "@signosoft/signpad-js";

// Use ref to access component methods (ok, clear, connect, etc. by signpadRef.value)
const signpadRef = ref<SignosoftSignpad | null>(null);

const signpadConfig = ref<SignpadConfig>({ lease: undefined });

const fetchLease = async () => {
  try {
    const response = await fetch("https://test.signosoft.com/api/v1/driver/leases", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        licenceKey: "YOUR-LICENSE-KEY",
        validityHours: 24,
        port: 4204,
      }),
    });

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`License server error: ${response.statusText} - ${errorText}`);
    }

    return await response.json();
  } catch (error) {
    console.error("Signosoft Signpad: License initialization failed", error);
    throw error;
  }
};

fetchLease()
  .then((lease) => {
    signpadConfig.value = {
      ...signpadConfig.value,
      lease,
    };
  });

</script>

<template>
  <div>
    <signosoft-signpad
      ref="signpadRef"
      :config="signpadConfig"
    ></signosoft-signpad>
  </div>
</template>

🍦 Vanilla JS Integration Guide

This guide describes how to integrate the @signosoft/signpad-js web component into a plain JavaScript project without any frameworks.

1. Installation

Install the package via npm:

npm install @signosoft/signpad-js

Or, if you are not using a bundler, you can include the script directly in your HTML (ensure the path points to the compiled bundle in node_modules or a CDN).

2. JavaScript Implementation

In Vanilla JS, you interact with the component by selecting it from the DOM and assigning the configuration directly to its config property.

import "@signosoft/signpad-js";

/**
 * INTELLISENSE SUPPORT (Optional)
 * Helps VS Code provide autocomplete for methods and properties.
 * @type {import('@signosoft/signpad-js').SignosoftSignpad}
 */
const pad = document.querySelector("signosoft-signpad");

// 1. Initial Configuration
pad.config = {
  lease: undefined,
};

const fetchLease = async () => {
  try {
    const response = await fetch(
      "https://test.signosoft.com/api/v1/driver/leases",
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          licenceKey: "YOUR-LICENSE-KEY",
          validityHours: 24,
          port: 4204,
        }),
      },
    );

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(
        `License server error: ${response.statusText} - ${errorText}`,
      );
    }

    return await response.json();
  } catch (error) {
    console.error("Signosoft Signpad: License initialization failed", error);
    throw error;
  }
};

fetchLease().then((lease) => {
  pad.config = { ...pad.config, lease };
});

3. HTML Structure

Add the custom element tag to your HTML and create the necessary control buttons.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Signosoft Signpad - Vanilla JS</title>
  </head>
  <body>
    <h1>Signosoft Signpad</h1>
    <!-- The Web Component -->
    <signosoft-signpad id="my-signpad"></signosoft-signpad>
    <!-- Main logic script -->
    <script type="module" src="main.js"></script>
  </body>
</html>

4. Key Concepts

  • Direct Property Assignment: Unlike some frameworks that use attributes, in Plain JS you should assign the configuration directly: element.config = { ... }.
  • Module System: Ensure your <script> tag has type="module" to use the import statement.
  • Methods: All methods like .connect(), .ok(), and .clear() are available directly on the DOM element object.
  • DOM Events: The component dispatches standard DOM events (like sign-ok, sign-clear) which you can listen to using addEventListener.

📋 Properties

The component is primarily configured through a single config property. This object controls everything from licensing and hardware behavior to UI visibility and localization.

| Property | Type | Default | Description | | :------- | :-------------- | :------ | :----------------------------------------------- | | config | SignpadConfig | {} | The main configuration object for the component. |

🔑 Core Options

| Option | Type | Required | Description | | :---------- | :------- | :------- | :---------------------------------------------------------------------------- | | lease | object | Yes | Lease payload returned from the lease API call. Mandatory for initialization. |

👁️ uiVisibilityOptions

Toggles the visibility of specific User Interface elements.

| Field | Type | Default | Description | | :--------------------------- | :-------- | :------ | :---------------------------------------------------------------- | | topBarVisible | boolean | true | Shows/hides the entire top navigation bar. | | topBarClearButtonVisible | boolean | false | Shows a "Clear" button in the top-left corner. | | topBarConnectButtonVisible | boolean | true | Shows the connect/disconnect button area in the top-right corner. | | bottomBarVisible | boolean | true | Shows/hides the entire bottom action bar. | | okButtonVisible | boolean | true | Shows the OK button in the bottom bar. | | clearButtonVisible | boolean | true | Shows the Clear button in the bottom bar. | | cancelButtonVisible | boolean | true | Shows the Cancel button in the bottom bar. | | canvasLineVisible | boolean | true | Shows the horizontal signature guide line on the canvas. | | deviceStatusTextVisible | boolean | true | Shows the name of the connected device (e.g., "Wacom STU-540"). | | additionalTextVisible | boolean | true | Shows helper status messages (e.g., "Ready to sign"). |

🖋️ canvasAndDrawingOptions

Adjusts the visual appearance of the digital ink.

| Field | Type | Default | Description | | :--------- | :------- | :-------- | :------------------------------------------ | | color | string | #000000 | The HEX color of the signature stroke. | | minWidth | number | 1 | The line thickness at minimum pen pressure. | | maxWidth | number | 3 | The line thickness at maximum pen pressure. |

Note: Since standard mice do not support physical pressure, the system emulates a normalized pressure of 0.5, ensuring consistent line rendering during fallback sessions.

🌐 languageOptions

Handles component localization. It can load external files or use inline definitions.

| Field | Type | Description | | :------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- | | lang | string | The active language code. Built-in translations are bundled for 'en', 'cs', and 'pt'; other languages can be supplied via langPath or translations. | | langPath | string | URL path to fetch translation files. Expects files in [path]/[lang].json format. | | translations | object | An inline object containing key-value pairs (e.g., { "OK": "Confirm signature" }). Overrides files. |

🌐 Localization & Translation Keys

Localization is driven from languageOptions, but you can also provide overrides at runtime:

  1. Set the language code in config.languageOptions.lang. English (en) is the fallback, Czech (cs) and Portuguese (pt) are shipped alongside it.
  2. Load a hosted file by pointing languageOptions.langPath to the directory that contains [lang].json. The loader will fetch ${langPath}/${lang}.json (or the exact file if you include the .json suffix).
  3. Override only specific phrases by passing a translations object—either a flat key map or a per-language map ({ en: {...}, cs: {...} }). Inline values take precedence over both built-in and fetched files.
  4. Dynamic placeholders (for example, {device} in TEXT_SIGNING_WITH_DEVICE) are replaced using the LocalizationManager.t helper. Keep the braces intact if you expect runtime interpolation.

The complete list of keys that can be translated is maintained in src/i18n/en.json. You can copy the structure when creating new language files or inline overrides. The defaults are:

| Key | Default (English) | | :--------------------------- | :-------------------------------------------------- | | OK | OK | | CLEAR | Clear | | CANCEL | Cancel | | CLEAR_SIGNATURE | Clear signature | | DISCONNECT | Disconnect | | CONNECT_SIGNPAD | Connect Signpad | | MOUSE | Mouse | | CONNECTED_UNKNOWN_DEVICE | Connected (Unknown Device) | | AUTO_CONNECTING | Auto-connecting to device... | | CONNECTING_TO_DEVICE | Connecting to your device... | | REVERTING_TO_DEFAULT | Reverting to default input... | | DISCONNECTING_DEVICE | Disconnecting device... | | COMPONENT_INITIALIZED | Component initialized. | | TEXT_START_SIGNING | Connect your device. | | TEXT_SIGN_WITH_PHYSICAL | Please sign using the device pen. | | TEXT_SIGN_WITH_MOUSE | Please sign using your mouse. | | TEXT_SIGN_GENERIC | Sign in the area above using mouse or pen. | | TEXT_SIGNING_WITH_DEVICE | Signing with {device} | | NO_DEVICE_FOUND | No device found. | | CONNECTION_ERROR | Connection error. | | ERROR_DISCONNECTION | Error during disconnection. | | ERROR_INSTANTIATING_DRIVER | Error instantiating driver. | | SIGNPAD_DISCONNECTED | Signpad disconnected. | | INVALID_LICENSE_KEY | Invalid license key. | | READY_TO_CONNECT | Ready to connect. | | SIGNPAD_DETECTED | Signpad detected. Click 'Connect Signpad' to begin. | | READY_TO_SIGN_MOUSE | Ready to sign. Use your mouse. | | READY_TO_SIGN_PHYSICAL | Ready to sign. Use the device pen. |

If you add any new keys, mirror them in every language file you provide to guarantee they fall back gracefully to English.

⚙️ Logic & Events

The component provides two ways to interact with internal processes.

🛠️ Action Handlers (actionHandlers)

These allow you to inject custom logic directly into the internal button flows. Your code runs alongside the component's internal logic.

| Handler | Arguments | Description | | :------------- | :---------------------------------- | :---------------------------------------------------------------------- | | handleOk | data?: ISignatureConfirmationData | Extends the internal OK button logic. Receives captured signature data. | | handleClear | — | Extends the internal Clear button logic. | | handleCancel | — | Extends the internal Cancel button logic. |

🔔 Event Callbacks (eventCallbacks)

Standard event listeners triggered after specific actions. Useful for observing the component from your application state.

| Callback | Payload | Description | | :------------- | :----------------------------------------------- | :------------------------------------------------------------------------------------------------- | | onPen | event: CustomEvent<IPenData> | Dispatched when a device or mouse fallback are in contact with component or signature pad display. | | onConnecting | event: CustomEvent<void> | Dispatched when a device is in loading state. | | onConnect | event: CustomEvent<{ deviceInfo: any }> | Dispatched when a device or mouse fallback connects. | | onDisconnect | event: CustomEvent<void> | Dispatched when the hardware connection is closed. | | onOk | event: CustomEvent<ISignatureConfirmationData> | Dispatched when signature is confirmed. | | onClear | event: CustomEvent<void> | Dispatched when the canvas has been cleared. | | onCancel | event: CustomEvent<void> | Dispatched when the user aborts the session. | | onError | event: CustomEvent<Error> | Dispatched on critical failures (lease, driver, connection, etc.). |

actionHandlers and eventCallbacks are separate hooks and can both be configured.


💡 Example Implementation

this.config = {
  lease: leasePayloadFromApi,
  canvasAndDrawingOptions: {
    color: "#1a1a1a",
  },
  actionHandlers: {
    handleOk: async (data) => {
      console.log("Saving signature data...", data);
    },
  },
  eventCallbacks: {
    onConnect: (e) =>
      console.log("Pad connected:", e.detail.deviceInfo.deviceName),
    onError: (event) => console.error("Signpad Error:", event.detail.message),
  },
};

🧩 Methods

The following methods are available on the component instance to control the signing process programmatically.

| Method | Returns | Description | | :--------------- | :------------------------------------------------- | :------------------------------------------------------------------------------- | | connect() | Promise<void> | Connects device to component | | disconnect() | Promise<void> | Disconnects device from component | | startSigning() | Promise<void> | Initializes a new signing session on the canvas and hardware. | | stopSigning() | Promise<void> | Low-level session stop that returns the raw driver payload. | | ok() | Promise<ISignatureConfirmationData \| undefined> | Finalizes the session, cleans the device screen, and returns the signature data. | | clear() | Promise<void> | Wipes the signature from the UI and hardware without ending the session. | | cancel() | Promise<void> | Aborts the current session and resets the component state. |


📜 connect()

This is the primary method to start using the Signpad. Because it uses the WebHID API, this must be triggered by a user gesture (like a button click) to satisfy browser security requirements.

The method first attempts to silently reconnect to a previously authorized device. If that fails, it opens the browser's device selection dialog and, if no physical device is selected, falls back to mouse/touch mode automatically.

Returns:

  • A Promise<void> that resolves once the connection attempt (or fallback) is complete.

📜 disconnect()

Safely terminates the communication channel with the signature tablet.

What happens during disconnect:

  1. The hardware driver is stopped and released.
  2. The internal cache of device information is cleared.
  3. The component UI transitions back to the DISCONNECTED state.
  4. Any active mouse listeners are removed.
  5. A SIGN_DISCONNECT event is dispatched.

💡 Best Practices

  • Initial Connection: Always call connect() from a click handler so the user can select their device from the browser list.
  • Cleanup: It is good practice to call disconnect() when the component is being destroyed or the user navigates away from the signing page to free up the USB port.

📜 startSigning(options?: IDrawingOptions)

Prepares the component for a new signature. It transitions the state to CONNECTING, resets any previous drawing data, and activates the pen input for either a physical device or mouse fallback.

// Example: Start a session with custom ink
await signpad.startSigning({
  color: "#0000FF",
  maxWidth: 4,
  minWidth: 2,
});

📜 ok()

This is the standard way to confirm a signature. It:

  1. Stops the signing process.
  2. Clears the physical device's screen (if connected).
  3. Dispatches the SIGN_OK event.
  4. Returns the final signature payload (coordinates, pressure, metadata).

Returned payload shape (ISignatureConfirmationData)

[
  points, // index 0: Data about each point
  imageBase64, // index 1: Image in base64
  metadata, // index 2: Information about tablet and canvas
];
// [0] Points structure
{
  absoluteX: number,
  absoluteY: number,
  inContact: boolean,
  pressure: number,
  ready: boolean,
  relativeX: number, // normalized 0..1
  relativeY: number, // normalized 0..1
  sequence: number,
  timestamp: number | bigint
}
// [1] imageBase64 — plain base64 PNG string
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA..."
// [2] Metadata structure
{
  canvas: {
    top: number,
    left: number,
    right: number,
    bottom: number,
    width: number,
    height: number,
    cssWidth: number,
    cssHeight: number,
    dpr: number
  },
  tablet: {
    name: string,
    aspectRatio: number,
    isCanvasStyleTablet: boolean,
    screenWidth: number,
    screenHeight: number,
    drawingArea: { x: number, y: number, width: number, height: number },
    serialNumber: Promise<string> | string,
    vendorId: number | null,
    productId: number | null
  }
}

handleOk(data) receives the same structure. onOk receives it in event.detail.

📜 onPen payload

onPen is emitted continuously while writing and provides a single IPenData object in event.detail.

{
  absoluteX: number,
  absoluteY: number,
  inContact: boolean,
  pressure: number,
  ready: boolean,
  relativeX: number, // normalized 0..1
  relativeY: number, // normalized 0..1
  sequence: number,
  timestamp: number | bigint
}

📜 stopSigning()

A low-level method that forces the driver to stop capturing data and returns the raw driver payload. Unlike ok(), it does not trigger the full "Finalization" flow (UI transitions or device screen clearing).

Note: stopSigning() intentionally exposes the unnormalized raw result, which is why it is documented as Promise<any>.

📜 clear()

Resets the drawing state on both the web canvas and the physical tablet's display. This allows the user to start their signature over without leaving the current session. It dispatches the SIGN_CLEAR event.

📜 cancel()

Stops the session immediately. It does not collect any signature data and resets the component to its ready state. This method dispatches the SIGN_CANCEL event.

🎨 Styling & Theming

The component uses a hybrid theming model:

  • It ships with complete default styles (works out of the box).
  • You can override the visual design through CSS variables.

✍️ Override via CSS

You can override variables in your stylesheet

📎 Copy-Paste Starter

Paste this directly into your app stylesheet and adjust values:

signosoft-signpad {
  /* Color Variables */
  --primary-color-0: #4e56ea;
  --primary-color-10: #7178ee;
  --background-color-0: #f1f2fd;
  --background-color-10: #e3e4fc;
  --text-color-0: #333e4a;
  --white-color: #ffffff;
  --grey-color: #b5b9be;

  /* Constraints */
  --min-height: 48px;
  --spacing-constraints: 16px 24px;

  /* CSS Variables */
  --sign-font-family: Arial, Helvetica, sans-serif;
  --sign-common-border-radius: 8px;

  /* Top Bar */
  --sign-top-bar-bg-base: var(--background-color-10);
  --sign-top-bar-text-base: var(--primary-color-0);
  --sign-top-bar-padding: var(--spacing-constraints);
  --sign-top-bar-min-height: var(--min-height);
  --sign-top-bar-border-top-left-radius: var(--sign-common-border-radius);
  --sign-top-bar-border-top-right-radius: var(--sign-common-border-radius);
  --sign-top-bar-border-bottom-left-radius: 0;
  --sign-top-bar-border-bottom-right-radius: 0;

  /* Canvas Area */
  --sign-canvas-bg-base: var(--background-color-0);
  --sign-canvas-wrapper-border-top-left-radius: 0;
  --sign-canvas-wrapper-border-top-right-radius: 0;
  --sign-canvas-wrapper-border-bottom-left-radius: 0;
  --sign-canvas-wrapper-border-bottom-right-radius: 0;

  /* Line */
  --sign-line-height: 22px;
  --sign-line-margin-bottom: 16px;
  --sign-line-border-base: var(--primary-color-10);
  --sign-line-additional-text-color: var(--text-color-0);
  --sign-line-margin: 0px 24px var(--sign-line-margin-bottom) 24px;
  --sign-canvas-line-text-font-size: 12px;
  --sign-canvas-height-offset: var(--sign-line-height);

  /* Bottom Bar */
  --sign-bottom-bar-bg-base: var(--background-color-10);
  --sign-bottom-bar-padding: var(--spacing-constraints);
  --sign-bottom-bar-min-height: var(--min-height);
  --sign-bottom-bar-gap: 12px;
  --sign-bottom-bar-border-top-left-radius: 0;
  --sign-bottom-bar-border-top-right-radius: 0;
  --sign-bottom-bar-border-bottom-left-radius: var(--sign-common-border-radius);
  --sign-bottom-bar-border-bottom-right-radius: var(
    --sign-common-border-radius
  );

  /* Button general settings */
  --sign-button-font-size: 16px;
  --sign-button-padding: 14px 16px;
  --sign-button-min-height: var(--min-height);
  --sign-button-border-radius: 8px;
  --sign-button-font-weight: 500;

  /* Primary Buttons (OK, Clear, Cancel) */
  --sign-button-primary-bg-base: var(--primary-color-0);
  --sign-button-primary-bg-hover: var(--primary-color-10);
  --sign-button-primary-bg-disabled: var(--grey-color);
  --sign-button-primary-text-base: var(--white-color);
  --sign-button-primary-text-hover: var(--white-color);
  --sign-button-primary-text-disabled: var(--white-color);

  /* Link Buttons (Connect signpad) */
  --sign-button-link-bg-base: transparent;
  --sign-button-link-bg-hover: var(--background-color-10);
  --sign-button-link-bg-disabled: transparent;
  --sign-button-link-text-base: var(--primary-color-0);
  --sign-button-link-text-hover: var(--primary-color-10);
  --sign-button-link-text-disabled: var(--grey-color);
  --sign-button-link-border-base: 1px solid var(--primary-color-0);
  --sign-button-link-border-hover: 1px solid var(--primary-color-10);
  --sign-button-link-border-disabled: 1px solid var(--grey-color);

  /* Device State Text Colors */
  --sign-device-state-text-color-connected: green;
  --sign-device-state-text-color-disconnected: red;

  /* Loading Overlay */
  --sign-loading-overlay-bg-color: rgba(255, 255, 255, 0.8);
  --sign-loading-overlay-text-color: var(--text-color-0);
  --sign-loading-overlay-spinner-color: var(--primary-color-0);
  --sign-loading-overlay-spinner-border-color: rgba(78, 86, 234, 0.1);
  --sign-loading-overlay-spinner-size: 30px;
}

📋 Full CSS Variable Reference

Base Colors & General

| Variable | Default | Description | | :---------------------------- | :------------------ | :---------------------------------------------- | | --primary-color-0 | #4e56ea | Primary brand color. | | --primary-color-10 | #7178ee | Primary hover/accent color. | | --background-color-0 | #f1f2fd | Secondary background color. | | --background-color-10 | #e3e4fc | Main bar background color. | | --text-color-0 | #333e4a | Main text color. | | --white-color | #ffffff | Pure white color. | | --grey-color | #b5b9be | Disabled state color. | | --sign-font-family | Arial, sans-serif | Global font family. | | --sign-common-border-radius | 8px | Shared radius token reused by bars and buttons. |

Layout & Constraints

| Variable | Default | Description | | :---------------------- | :---------- | :------------------------------------- | | --min-height | 48px | Minimum height for bars and buttons. | | --spacing-constraints | 16px 24px | Default padding/margin for containers. |

Top Bar

| Variable | Default | Description | | :------------------------------------------ | :--------------------------------- | :---------------------------------- | | --sign-top-bar-bg-base | var(--background-color-10) | Background color of the top bar. | | --sign-top-bar-text-base | var(--primary-color-0) | Text color in the top bar. | | --sign-top-bar-padding | var(--spacing-constraints) | Inner padding of the top bar. | | --sign-top-bar-min-height | var(--min-height) | Minimum height of the top bar. | | --sign-top-bar-border-top-left-radius | var(--sign-common-border-radius) | Top-left radius of the top bar. | | --sign-top-bar-border-top-right-radius | var(--sign-common-border-radius) | Top-right radius of the top bar. | | --sign-top-bar-border-bottom-left-radius | 0 | Bottom-left radius of the top bar. | | --sign-top-bar-border-bottom-right-radius | 0 | Bottom-right radius of the top bar. |

Canvas & Signature Line

| Variable | Default | Description | | :------------------------------------------------- | :--------------------------------------------- | :--------------------------------------------------------------------------- | | --sign-canvas-bg-base | var(--background-color-0) | Background color of the drawing area. | | --sign-canvas-wrapper-border-top-left-radius | 0 | Top-left canvas radius, typically rounded when the top bar is hidden. | | --sign-canvas-wrapper-border-top-right-radius | 0 | Top-right canvas radius, typically rounded when the top bar is hidden. | | --sign-canvas-wrapper-border-bottom-left-radius | 0 | Bottom-left canvas radius, typically rounded when the bottom bar is hidden. | | --sign-canvas-wrapper-border-bottom-right-radius | 0 | Bottom-right canvas radius, typically rounded when the bottom bar is hidden. | | --sign-line-height | 22px | Vertical offset/height for the guide line. | | --sign-line-margin-bottom | 16px | Bottom spacing used in canvas line layout. | | --sign-line-border-base | var(--primary-color-10) | Color of the signature guide line. | | --sign-line-additional-text-color | var(--text-color-0) | Color of the helper text below the line. | | --sign-line-margin | 0px 24px var(--sign-line-margin-bottom) 24px | Spacing around the guide line. | | --sign-canvas-line-text-font-size | 12px | Font size for guide line labels. | | --sign-canvas-height-offset | var(--sign-line-height) | Canvas offset calculation for the guide line. |

Bottom Bar

| Variable | Default | Description | | :--------------------------------------------- | :--------------------------------- | :--------------------------------------- | | --sign-bottom-bar-bg-base | var(--background-color-10) | Background color of the bottom bar. | | --sign-bottom-bar-padding | var(--spacing-constraints) | Inner padding of the bottom bar. | | --sign-bottom-bar-min-height | var(--min-height) | Minimum height of the bottom bar. | | --sign-bottom-bar-gap | 12px | Space between buttons in the bottom bar. | | --sign-bottom-bar-border-top-left-radius | 0 | Top-left radius of the bottom bar. | | --sign-bottom-bar-border-top-right-radius | 0 | Top-right radius of the bottom bar. | | --sign-bottom-bar-border-bottom-left-radius | var(--sign-common-border-radius) | Bottom-left radius of the bottom bar. | | --sign-bottom-bar-border-bottom-right-radius | var(--sign-common-border-radius) | Bottom-right radius of the bottom bar. |

Buttons (General)

| Variable | Default | Description | | :---------------------------- | :------------------ | :----------------------------- | | --sign-button-font-size | 16px | Font size for all buttons. | | --sign-button-padding | 14px 16px | Inner padding for all buttons. | | --sign-button-min-height | var(--min-height) | Minimum height for buttons. | | --sign-button-border-radius | 8px | Border radius for all buttons. | | --sign-button-font-weight | 500 | Font weight for all buttons. |

Primary Buttons (OK, Clear, Cancel)

| Variable | Description | | :------------------------------------ | :----------------------------------- | | --sign-button-primary-bg-base | Background color of primary buttons. | | --sign-button-primary-bg-hover | Hover background color. | | --sign-button-primary-bg-disabled | Disabled background color. | | --sign-button-primary-text-base | Text color for primary buttons. | | --sign-button-primary-text-hover | Hover text color. | | --sign-button-primary-text-disabled | Disabled text color. |

Link/Connect Buttons

| Variable | Default | Description | | :----------------------------------- | :---------------------------------- | :------------------------------------------- | | --sign-button-link-bg-base | transparent | Background color for secondary/link buttons. | | --sign-button-link-bg-hover | var(--background-color-10) | Hover background color. | | --sign-button-link-bg-disabled | transparent | Disabled background color. | | --sign-button-link-text-base | var(--primary-color-0) | Text color for secondary/link buttons. | | --sign-button-link-text-hover | var(--primary-color-10) | Hover text color. | | --sign-button-link-text-disabled | var(--grey-color) | Disabled text color. | | --sign-button-link-border-base | 1px solid var(--primary-color-0) | Border for secondary/link buttons. | | --sign-button-link-border-hover | 1px solid var(--primary-color-10) | Hover border color. | | --sign-button-link-border-disabled | 1px solid var(--grey-color) | Disabled border color. |

Status & Overlays

| Variable | Default | Description | | :-------------------------------------------- | :------------------------- | :--------------------------------- | | --sign-device-state-text-color-connected | green | Text color when device is ready. | | --sign-device-state-text-color-disconnected | red | Text color when disconnected. | | --sign-loading-overlay-bg-color | rgba(255, 255, 255, 0.8) | Background of the loading spinner. | | --sign-loading-overlay-text-color | var(--text-color-0) | Loading overlay text color. | | --sign-loading-overlay-spinner-color | var(--primary-color-0) | Color of the animated spinner. | | --sign-loading-overlay-spinner-border-color | rgba(78, 86, 234, 0.1) | Base border color of spinner ring. | | --sign-loading-overlay-spinner-size | 30px | Size of the spinner icon. |

💬 Feedback & Support

We are constantly working to improve our components and drivers. Your feedback is essential to us. Whether you found a bug, have a feature request, or need technical assistance, please reach out to us:

🛠️ Contributing

Commit naming convention

  • Every commit message must start with Jira task id and category:
    • MAIN-000/<category>: <summary>
  • For work in progress:
    • MAIN-000/<category>: WIP - <summary>

Allowed categories:

  • feat: adding a new feature
  • fix: fixing a bug
  • refactor: performance/readability/maintainability change
  • chore: docs, formatting, tests, cleanup, tooling
  • merge: branch merge into main

Use infinitive verb form in commit summaries:

  • RIGHT: add, fix, remove, update, refactor
  • WRONG: Continuous tense: adding, removing Past tense: added, fixed

Examples:

git commit -m "MAIN-000/feat: add new button component; add button to templates"
git commit -m "MAIN-000/fix: add stop directive to button component to prevent propagation"
git commit -m "MAIN-000/refactor: rewrite button component in TypeScript"
git commit -m "MAIN-000/chore: write button documentation"
git commit -m "MAIN-000/merge: new button"
git commit -m "MAIN-000/feat: WIP - basic signing functionality"

Versioning and release commits

Follow Semantic Versioning:

  • MAJOR (x.0.0): breaking changes
  • MINOR (x.y.0): backward-compatible feature set
  • PATCH (x.y.z): backward-compatible bug fixes

Commit naming for version bumps:

  • Version-only change: use chore
  • Version bump with actual code/features in same commit: use feat/fix/refactor based on dominant change
  • For release commits, include both versions in message: release from <old> to <new>

Example (version bump with feature changes):

git commit -m "MAIN-000/feat: release from 0.2.4 to 0.3.0 - add signature method"

Example (version-only commit):

git commit -m "MAIN-000/chore: release from 0.2.4 to 0.3.0"

How version increment works:

  • PATCH (x.y.Z): increase patch only (1.4.2 -> 1.4.3)
  • MINOR (x.Y.0): increase minor, reset patch (1.4.9 -> 1.5.0)
  • MAJOR (X.0.0): increase major, reset minor and patch (1.9.7 -> 2.0.0)

Examples:

# patch
git commit -m "MAIN-000/fix: release from 1.0.0 to 1.0.1 - fix onPen throttle edge case"

# minor
git commit -m "MAIN-000/feat: release from 1.1.1 to 1.2.0 - add lease refresh helper"

# major
git commit -m "MAIN-000/refactor: release from 1.1.1 to 2.0.0 - remove legacy API"

📄 License

Proprietary Commercial License

Copyright © 2026, Signosoft. All rights reserved.

This software is proprietary to Signosoft and is protected by copyright laws. It is not open source.

🔐 Commercial Usage

A valid, paid, and active commercial license agreement with Signosoft is strictly required for the use, operation, reproduction, distribution, or deployment of this software in any environment (including development, testing, staging, and production).

📜 Key Terms

  • Unauthorized Use: Any use without a current, fully paid license is expressly prohibited and constitutes a violation of our intellectual property rights.
  • Legal Action: Signosoft reserves the right to pursue legal action to enforce its rights and seek damages for unauthorized use.
  • Restrictions: You may not reverse-engineer, decompile, or disassemble this software except as permitted by applicable law.

For information on how to obtain a valid commercial license, pricing, and support, please contact us at [email protected].

See the LICENSE file for the full legal text.