@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
🔐 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
- Generate/get your license key in Signosoft portal.
- Request a lease from the Signosoft lease API.
- 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-jsOr using your preferred manager:
yarn add @signosoft/signpad-jspnpm 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
@typesneeded.
🚀 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-js2. 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-js2. 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-js2. 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-jsOr, 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 hastype="module"to use theimportstatement. - 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 usingaddEventListener.
📋 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:
- Set the language code in
config.languageOptions.lang. English (en) is the fallback, Czech (cs) and Portuguese (pt) are shipped alongside it. - Load a hosted file by pointing
languageOptions.langPathto the directory that contains[lang].json. The loader will fetch${langPath}/${lang}.json(or the exact file if you include the.jsonsuffix). - Override only specific phrases by passing a
translationsobject—either a flat key map or a per-language map ({ en: {...}, cs: {...} }). Inline values take precedence over both built-in and fetched files. - Dynamic placeholders (for example,
{device}inTEXT_SIGNING_WITH_DEVICE) are replaced using theLocalizationManager.thelper. 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.). |
actionHandlersandeventCallbacksare 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:
- The hardware driver is stopped and released.
- The internal cache of device information is cleared.
- The component UI transitions back to the
DISCONNECTEDstate. - Any active mouse listeners are removed.
- A
SIGN_DISCONNECTevent 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:
- Stops the signing process.
- Clears the physical device's screen (if connected).
- Dispatches the
SIGN_OKevent. - 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 asPromise<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:
- 📧 Support Email: [email protected]
- 🌐 Official Website: www.signosoft.com
🛠️ 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 featurefix: fixing a bugrefactor: performance/readability/maintainability changechore: docs, formatting, tests, cleanup, toolingmerge: branch merge intomain
Use infinitive verb form in commit summaries:
- RIGHT:
add,fix,remove,update,refactor - WRONG: Continuous tense:
adding,removingPast 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 changesMINOR(x.y.0): backward-compatible feature setPATCH(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/refactorbased 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.
