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

@toughclicks/js-client-sdk

v2.1.1

Published

ToughClicks JS SDK for client integrtions

Downloads

1,292

Readme

📦 Documentation

Our comprehensive documentation is hosted here at https://developers.toughclicks.com.

Getting Help

If you need help using our library, please contact our team via https://developers.toughclicks.com/docs/getting-help

ToughClicks JavaScript SDK

A JavaScript SDK for handling document acceptance and verification with support for multiple packets.

Features

  • Multi-Packet Support: Handle multiple packet IDs with individual display options
  • Per-Packet Display Options: Configure different display methods, containers, and settings for each packet
  • Optional Packets: Mark packets as optional - users don't need to check them for validation
  • Document Acceptance: Track user acceptance of documents across multiple packets
  • User Verification: Verify user compliance across all packets
  • Flexible Rendering: Support for individual, group, and scroll display methods
  • Event-Driven: Listen for validation and acceptance events

Installation

npm install @toughclicks/js-client-sdk

Importing CSS

The SDK requires CSS to be imported for proper styling. Import it in your application:

// ES Modules / Vite / Webpack
import "@toughclicks/js-client-sdk/toughclicks.css";

// Or use the full path
import "@toughclicks/js-client-sdk/build/toughclicks.css";

If you're not using a framework that supports CSS imports in JavaScript, reference the CDN:

<!-- optionally add css -->
<link
  rel="stylesheet"
  href="https://cdn.toughclicks.com/lib/<version>/toughclicks.css"
/>

Basic Usage

Single Packet (Legacy)

import { ToughClicks, TCDisplayMethod } from "toughclicks-js";

const toughClicks = new ToughClicks(
  "your-token-here",
  "single-packet-id",
  true, // debug mode
  "production" // environment
);

// Set display options
toughClicks.setDisplayOptions({
  containerId: "my-container",
  signerIdSelector: "user-id-input",
  signerId: null,
  displayMethod: TCDisplayMethod.individual,
  shouldOpenModal: true,
  manualAcceptance: false,
});

// Render the packet
toughClicks.render();

Multiple Packets (New)

import { ToughClicks, TCDisplayMethod } from "toughclicks-js";

const toughClicks = new ToughClicks(
  "your-token-here",
  ["packet1-id", "packet2-id", "packet3-id"],
  true, // debug mode
  "production", // environment
  undefined, // getPageContext (default)
  [
    {
      packetId: "packet1-id",
      displayOptions: {
        containerId: "packet1-container",
        signerIdSelector: "user-id-1",
        signerId: null,
        displayMethod: TCDisplayMethod.individual,
        shouldOpenModal: true,
        manualAcceptance: false,
      },
    },
    {
      packetId: "packet2-id",
      displayOptions: {
        containerId: "packet2-container",
        signerIdSelector: "user-id-2",
        signerId: null,
        displayMethod: TCDisplayMethod.group,
        shouldOpenModal: false,
        manualAcceptance: true,
      },
    },
    {
      packetId: "packet3-id",
      displayOptions: {
        containerId: "packet3-container",
        signerIdSelector: "user-id-3",
        signerId: null,
        displayMethod: TCDisplayMethod.scroll,
        shouldOpenModal: true,
        manualAcceptance: false,
      },
    },
  ]
);

// Render all packets
toughClicks.render();

Optional Packets

You can mark packets as optional, meaning users don't need to check them for the overall validation to pass. Optional packets will only send API calls if the user actually checks them.

import { ToughClicks, TCDisplayMethod } from "toughclicks-js";

const toughClicks = new ToughClicks(
  "your-token-here",
  ["required-terms", "optional-marketing"],
  true, // debug mode
  "production", // environment
  undefined, // getPageContext (default)
  [
    {
      packetId: "required-terms",
      displayOptions: {
        containerId: "required-container",
        signerIdSelector: "user-id",
        signerId: null,
        displayMethod: TCDisplayMethod.individual,
        shouldOpenModal: false,
        manualAcceptance: false,
        optional: false, // Required packet (default)
      },
    },
    {
      packetId: "optional-marketing",
      displayOptions: {
        containerId: "optional-container",
        signerIdSelector: "user-id",
        signerId: null,
        displayMethod: TCDisplayMethod.individual,
        shouldOpenModal: false,
        manualAcceptance: false,
        optional: true, // Optional packet
      },
    },
  ]
);

// Event listeners
toughClicks.on("tc-valid", (state) => {
  // This will fire when all REQUIRED packets are valid
  // Optional packets don't affect this validation
  console.log("All required packets are valid!");
});

toughClicks.on("tc-accepted", (state) => {
  // This will fire when all checked packets are accepted
  // Only sends API calls for packets that were actually checked
  console.log("Packets accepted!");
});

Key Points:

  • Optional packets don't affect the tc-valid event
  • API calls are only sent for packets that were actually checked
  • Users can proceed with only required packets checked
  • Optional packets provide opt-in functionality for additional consent

API Reference

Constructor

new ToughClicks(
    token: string,
    packetIds: string | string[],
    debug?: boolean,
    environment?: TCEnvironment,
    getPageContext?: () => TCContextState,
    packetDisplayOptions?: TCPacketDisplayOptions[]
)

Methods

Core Methods

  • render(): Promise<boolean> - Render all packets
  • accept(): Promise<boolean> - Accept all packets
  • verify(userId: string): Promise<TCVerificationResponse[]> - Verify user across all packets

Display Options (Per-Packet)

  • setPacketDisplayOptions(packetId: string, options: TCDisplayOptions): boolean - Set display options for a specific packet
  • getPacketDisplayOptions(packetId: string): TCDisplayOptions | null - Get display options for a specific packet
  • setAllPacketDisplayOptions(packetDisplayOptions: TCPacketDisplayOptions[]): boolean - Set display options for multiple packets

State Management

  • setCustomData(customData: object): boolean - Set custom data for all packets
  • setSignerEmailAddress(email: string): boolean - Set signer email for all packets
  • setDynamicData(dynamicData: object | null): boolean - Set dynamic data for all packets

Utility Methods

  • setDebug(debug: boolean): boolean - Enable/disable debug mode
  • setTTL(ttl: number): boolean - Set cache TTL
  • clearCache(): boolean - Clear all cached data

Event Handling

  • on(event: TCEventTypes, callback: Function): void - Register event listener

Events

  • tc-valid - Emitted when validation state changes
  • tc-accepted - Emitted when all packets are accepted
  • tc-internal-error - Emitted on internal errors

Types

TCDisplayOptions

interface TCDisplayOptions {
  containerId?: string;
  signerIdSelector: string | null;
  signerId: string | null;
  displayMethod: TCDisplayMethod | null;
  shouldOpenModal: boolean | null;
  manualAcceptance: boolean | false;
  optional?: boolean; // Mark packet as optional (default: false)
}

TCPacketDisplayOptions

interface TCPacketDisplayOptions {
  packetId: string;
  displayOptions: TCDisplayOptions;
}

TCDisplayMethod

enum TCDisplayMethod {
  individual = "individual",
  group = "group",
  scroll = "scroll",
}

Display Methods

Individual

Documents are displayed as separate checkboxes, each requiring individual acceptance.

Group

All documents in a packet are grouped into a single checkbox for collective acceptance.

Scroll

Documents are displayed in scrollable containers that must be scrolled to the bottom before acceptance is allowed.

Examples

Mixed Display Methods

const toughClicks = new ToughClicks(
  "token",
  ["terms-packet", "privacy-packet", "consent-packet"],
  true,
  "production",
  undefined,
  [
    {
      packetId: "terms-packet",
      displayOptions: {
        containerId: "terms-container",
        signerIdSelector: "user-id",
        displayMethod: TCDisplayMethod.scroll,
        shouldOpenModal: true,
        manualAcceptance: false,
      },
    },
    {
      packetId: "privacy-packet",
      displayOptions: {
        containerId: "privacy-container",
        signerIdSelector: "user-id",
        displayMethod: TCDisplayMethod.group,
        shouldOpenModal: false,
        manualAcceptance: true,
      },
    },
    {
      packetId: "consent-packet",
      displayOptions: {
        containerId: "consent-container",
        signerIdSelector: "user-id",
        displayMethod: TCDisplayMethod.individual,
        shouldOpenModal: true,
        manualAcceptance: false,
      },
    },
  ]
);

Event Handling

toughClicks.on("tc-valid", (state) => {
  console.log("All packets valid:", state.allPacketsValid);
  if (state.allPacketsValid) {
    // Enable submit button
    document.getElementById("submit-btn").disabled = false;
  }
});

toughClicks.on("tc-accepted", (state) => {
  console.log("All packets accepted:", state.allPacketsAccepted);
  if (state.allPacketsAccepted) {
    // Proceed to next step
    window.location.href = "/next-page";
  }
});

Migration from Single Packet

If you're migrating from the single packet API:

  1. Constructor: Change from new ToughClicks(token, packetId, ...) to new ToughClicks(token, [packetId], ...)
  2. Display Options: Use setPacketDisplayOptions(packetId, options) instead of setDisplayOptions(options)
  3. Verification: The verify() method now returns an array of results instead of a single result
  4. Events: Event handlers now receive TCMultiPacketState instead of TCState

License

MIT License - see LICENSE file for details.