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

@soyio/soyio-widget

v2.22.1

Published

<h1 align="center">Soyio Widget</h1>

Readme

Table of Contents

Installation

Install using npm! (or your favorite package manager)

# Using npm
npm install @soyio/soyio-widget

# Using yarn
yarn add @soyio/soyio-widget

# Using pnpm
pnpm add @soyio/soyio-widget

Usage

Integrate the widget into your frontend framework using the script below. Ensure to replace placeholders (e.g., <request>, <company id>) with actual values relevant to your implementation.


Modules

The Soyio Widget provides several modules that you can integrate into your application:

  • Consent Request Box: Embed consent requests directly within your webpage
  • Privacy Center: Embed the Privacy Center inside your page with customizable features
  • Disclosure Request: Verify users and collect required data through validation or authentication
  • Signature Attempt: Enable users to digitally sign documents after authentication
  • Auth Request: Authenticate users using access keys or facial video

Consent Request Box

📖 Integration Guide

The ConsentBox is a component that allows you to embed a consent request directly within your webpage, rather than opening it in a popup window. This is particularly useful when you want to integrate the consent flow seamlessly into your application's interface.

<!-- Add a container div where the consent request will be mounted -->
<div id="consent-request-box"></div>

<script>
  import { ConsentBox } from "@soyio/soyio-widget";

  // Configuration for the consent request
  const consentOptions = {
    consentTemplateId: "<consent template id>",
    onEvent: (data) => console.log(data),
    isSandbox: true, // Optional
    appearance: {}, // Optional
    actionToken: "<action token>", // Optional
    entityId: "<entity id>", // Optional
    context: "<context>", // Optional
    onReady: () => console.log("ConsentBox is ready"), // Optional
    optionalReconsentBehavior: "notice", // Optional
    mandatoryReconsentBehavior: "notice", // Optional
  };

  // Wait for DOM to be fully loaded
  document.addEventListener("DOMContentLoaded", () => {
    // Create and mount the consent request box
    const consentBox = new ConsentBox(consentOptions);
    consentBox.mount("#consent-request-box");
  });
</script>

Consent Request Box Events

The onEvent follows the following format:

{
  eventName: 'CONSENT_CHECKBOX_CHANGE',
  isSelected: boolean,
  actionToken: string,
}

Methods

  • getState(): Returns the current state of the consent box. The returned object has the following structure:
{
  isSelected: boolean,
  actionToken: string | null,
}

Attribute Descriptions

  • consentTemplateId: Identifier of consent template. It must start with 'constpl_'.

  • isSelected: Boolean value indicating whether the consent checkbox is selected or not.

  • appearance: Customize the appearance of the iframe. Learn more.

  • actionToken: In case of losing the state of the consent (i.e. page reload), you can use a previously generated actionToken to restore the state of the consent.

  • entityId: Identifier of the entity associated with a ConsentAction. If provided and a consent was previously granted by this entity, the UI will display a message indicating that consent has already been given.

  • context: Additional information that will be saved with the consent. Useful when you want to track the consent from a specific context.

  • onReady: Optional callback that executes when the consent box is ready to use. You can use this to handle logic when the iframe is not mounted yet.

  • optionalReconsentBehavior: What should happen when the consent is initialized with an entityId that has already given consent on an optional category.

    • notice will show a message letting the user know that they have already given consent,
    • askAgain will show the consent as if it wasn't given in the first place,
    • hide will not show the consent at all.

    We strongly recommend using notice so the user doesn't have to give the consent again and knows what they have already given consent to.

  • mandatoryReconsentBehavior: What should happen when the consent is initialized with an entityId that has already given consent on a mandatory category.

    • notice will show a message letting the user know that they have already given consent,
    • askAgain will show the consent as if it wasn't given in the first place,

    We don't support hiding the mandatory consent, and we strongly recommend using notice so the user doesn't have to give the consent again and knows what they have already given consent to.

Privacy Center

📖 Integration Guide

The PrivacyCenterBox lets you embed the Privacy Center inside your page. You can scope which features to show and which data subjects are relevant to your interface. For more info check our docs.

<!-- Add a container div where the Privacy Center will be mounted -->
<div id="privacy-center-box"></div>

<script>
  import { PrivacyCenterBox } from "@soyio/soyio-widget";

  // Configuration for the Privacy Center
  const privacyCenterOptions = {
    // Choose ONE of the following authentication modes:
    // 1) Public mode
    companyId: "<company id>", // e.g. com_...

    // 2) Authenticated mode
    // sessionToken: "<session token>",

    // Feature flags (optional)
    enabledFeatures: ["DataSubjectRequest", "ConsentManagement"],

    // DSR rights to show (optional)
    // When omitted, the DSR form will use arsop right as default
    enabledRights: ["arsop"],

    // Request reference (optional)
    // Will be attached to data subject requests
    requestReference: "<reference>", // e.g. some uuid or id to match our created records with your frontend flows

    // Limit consent view to specific data subjects (optional)
    dataSubjects: ["customer", "employee"],

    // File upload configuration (optional)
    fileRequisites: {
      allowedExtensions: ["pdf", "png", "jpeg", "jpg"],
      maxFileSize: 5 * 1024 * 1024, // 5MB
    },

    // Redec operation options (optional unless "redec" is in enabledRights)
    redecOperationIds: [
      { id: "op_update", label: "Update" },
      { id: "op_rectification", label: "Rectification" },
    ],

    // Common options
    onEvent: (event) => console.log(event),
    onReady: () => console.log("PrivacyCenterBox is ready"), // Optional
    isSandbox: true, // Optional
    appearance: {}, // Optional
  };

  // Wait for DOM to be fully loaded
  document.addEventListener("DOMContentLoaded", () => {
    const privacyCenter = new PrivacyCenterBox(privacyCenterOptions);
    privacyCenter.mount("#privacy-center-box");
  });
</script>

Attribute Descriptions

  • sessionToken: Use this to authenticate a session directly.
  • companyId: The company identifier. Must start with com_. Use this when Privacy Center is mounted in a non authenticated environment.
  • enabledFeatures: Optional array of features to show. Supported values: "DataSubjectRequest", "ConsentManagement".
  • enabledRights: Optional array of rights for the Data Subject Request (DSR) form. Supported values: "arsop", "redec". When multiple values are provided, the form starts with a right selection step. When a single value is provided, the selection step is skipped. When omitted, the form defaults to arsop rights.
  • requestReference: Optional string, intended to be a reference of the current session. It will be attached to created data subject requests.
  • dataSubjects: Optional array of data subject categories. When present, the consent management view only shows consent for the specified categories. Supported values include: "anonymous_user", "citizen_voter", "commuter", "consultant", "customer", "employee", "job_applicant", "next_of_kin", "passenger", "patient", "prospect", "shareholder", "supplier_vendor", "trainee", "visitor".
  • fileRequisites: Optional object to configure file upload constraints.
    • allowedExtensions: Array of allowed file extensions (e.g. ['pdf', 'jpg']). Default: ['pdf', 'png', 'jpeg', 'jpg'].
    • maxFileSize: Maximum file size in bytes. Default: 5 * 1024 * 1024 (5MB).
  • redecOperationIds: Optional array of { id, label } values for the Redec operation select. Required if redec right is included in enabledRights param.
  • isSandbox: Whether to use the sandbox environment. Defaults to false.
  • consentControl: Optional, controls the visual interaction for consent toggles. Values: 'switch' (default) or 'checkbox'.
  • consentMode: Optional, controls how consent changes are committed. Values: 'immediate' (default) or 'batch' (save multiple changes at once).
  • consentRetentionPeriod: Optional, specifies a duration during which a consent cannot be revoked after being granted. Format: "<value> <unit>". Supported units: day, week, month, year (and their plural forms). Example: '30 days', '1 week'.
  • showBatchConsentConfirmation: Optional boolean, whether to show a confirmation dialog before saving consent changes in batch mode.
  • appearance: Customize the iframe appearance. See Appearance section below.
  • onEvent: Callback that receives events from the iframe.
  • onReady: Optional callback fired when the iframe becomes ready.

Note:

  • When sessionToken is provided, do not pass companyId.

Privacy Center Events

  • REQUEST_SUBMITTED: This event occurs when a user successfully submits a Data Subject Request. The event object includes:
    • eventName: The name of the event, in this case, 'REQUEST_SUBMITTED'.
    • kind: The kind of the Data Subject Request submitted. Supported values are: access, opposition, rectification, suppression and portability

Disclosure Request

📖 Integration Guide

[!NOTE] In Safari browsers, disclosure requests can only be opened as a result of a direct user interaction (like a click event). This is due to Safari's security policies regarding popup windows. Always ensure the disclosure request initialization is triggered by a user action when supporting Safari browsers.

A disclosure_request is a process that a user goes through where they are verified, and then they share the necessary data as required by each company. This verification can happen in one of the following two ways:

  1. Validation: Through document validation and facial video. This occurs when a user has never been verified before with Soyio.

  2. Authentication: Through an access key (passkey) or facial video. This can occur when a user has already been validated previously with Soyio.

To instantiate this process in the code, you have two options:

1. Disclosure Requests On-the-fly

This doesn't require any previous setup. Given your company and disclosure template IDs, you can create disclosure requests freely when the user starts the widget.

<button id="start-disclosure-request">Start disclosure request</button>

<script>
  import { SoyioWidget } from "@soyio/soyio-widget";

  // Widget configuration
  const widgetConfig = {
    request: "disclosure",
    configProps: {
      companyId: "<company id>",
      userReference: "<user identifier of company>",
      userEmail: "<user email>",
      templateId: "<template id>",
      customColor: "<custom color>",
    },
    onEvent: (data) => console.log(data),
    isSandbox: true,
  };

  // Function to create the widget
  function initWidget() {
    new SoyioWidget(widgetConfig);
  }

  // Add event listener to the button to create the widget on click
  document
    .getElementById("start-disclosure-request")
    .addEventListener("click", initWidget);
</script>

Optional props:

  • userEmail
  • customColor.

2. Created Disclosure Request

You can alternatively create a disclosure request beforehand with some matchers to make sure the person completing the request matches the one that your application thinks it is.

For more details about the use case, please refer to the documentation.

To use this option, simply specify the disclosure request ID along with any optional parameters:

<button id="start-disclosure-request">Start disclosure request</button>

<script>
  import { SoyioWidget } from "@soyio/soyio-widget";

  // Widget configuration
  const widgetConfig = {
    request: "disclosure",
    configProps: {
      disclosureRequestId: "<disclosure request id>",
      customColor: "<custom color>",
    },
    onEvent: (data) => console.log(data),
    isSandbox: true,
  };

  // Function to create the widget
  function initWidget() {
    new SoyioWidget(widgetConfig);
  }

  // Add event listener to the button to create the widget on click
  document
    .getElementById("start-disclosure-request")
    .addEventListener("click", initWidget);
</script>

Optional properties:

  • customColor

Note: User and template properties are not specified here because they must be specified when creating the disclosure request beforehand.

Disclosure Request Events

The onEvent callback is designed to handle various events that occur during widget interaction. Specifically, it receives detailed information upon the successful completion of user request. Here are the events it handles:

  • DISCLOSURE_REQUEST_SUCCESSFUL: This event occurs when a user successfully completes a disclosure_request. The identity verification could have been a validation or authentication.

    • eventName: The name of the event, in this case, 'DISCLOSURE_REQUEST_SUCCESSFUL'.
    • verificationMethod: Takes the values of authentication or validation.
    • identityId: The unique identifier for the verified identity.
    • userReference: The reference identifier for the user, facilitating the association of the event with the user within the company's context.
  • DENIED_CAMERA_PERMISSION: Event triggered when user denies camera permissions. It closes the widget.

  • UNEXPECTED_ERROR: Event triggered when user exits because of an unexpected error.

  • WIDGET_CLOSED: This event occurs when the user closes the Soyio pop up. The event object is as follows:

    • { eventName: 'WIDGET_CLOSED' }.
  • WIDGET_OPENED: This event occurs when the user closes the Soyio pop up. The event object is as follows:

    • { eventName: 'WIDGET_CLOSED' }.

Disclosure Request Attribute Descriptions

  • companyId: The unique identifier for the company, must start with 'com_'.
  • userReference: A reference identifier provided by the company for the user engaging with the widget. This identifier is used in events (onEvent and webhooks) to inform the company which user the events are associated with.
  • userEmail: The user's email address. If not provided, Soyio will prompt the user to enter their email.
  • templateId: Identifier of template. Specifies the order and quantity of documents requested from the user, as well as the mandatory data that the user is asked to share with the company. It must start with 'dtpl_'.
  • disclosureRequestId: If created beforehand, you can target a specific disclosure request that the user must complete. It is useful if you need to match some data between the disclosure process and your database records. It must start with 'dreq_'
  • identityId: This identifier must start with 'id_' and signifies the user's identity.
  • isSandbox: Indicates if the widget should operate in sandbox mode, defaulting to false.
  • onEvent: A callback function triggered upon event occurrences, used for capturing and logging event-related data.
  • customColor: A hex code string that specifies the base color of the interface.

Disclosure Request Box

Use DisclosureRequestBox when you want to keep the disclosure flow inside your page, without popup windows.

This embedded API currently supports disclosure flows created in advance (existing disclosure requests only).

<div id="embedded-disclosure"></div>

<script>
  import { DisclosureRequestBox } from "@soyio/soyio-widget";

  const widget = new DisclosureRequestBox({
    disclosureRequestId: "<disclosure request id>",
    customColor: "#0F172A", // Optional
    onEvent: (event) => {
      console.log("DisclosureRequestBox event:", event);
    },
    onReady: () => {
      console.log("DisclosureRequestBox is ready");
    },
    minHeight: "640px", // Optional
    height: "720px", // Optional
    isSandbox: true, // Optional
  });

  widget.mount("#embedded-disclosure");

  // Optional cleanup
  // widget.unmount();
</script>

Passkey registration and passkey authentication are handled through a temporary popup tunnel and then return control to the embedded iframe flow.

Signature Attempt

📖 Integration Guide

The signature_attempt is a process where, using a previously created signature_attempt_id, a request is initiated in which a user can digitally sign a document. To sign the document, the user must be authenticated. This authentication can occur either through an access key or facial video. It's important to note that for this request, the user must have been previously verified with Soyio.

<button id="start-signature-attempt">Start signature attempt</button>

<script>
  import { SoyioWidget } from "@soyio/soyio-widget";

  // Widget configuration
  const widgetConfig = {
    request: "signature",
    configProps: {
      signatureAttemptId: "<signature attempt id>",
      customColor: "<custom color>",
    },
    onEvent: (data) => console.log(data),
    isSandbox: true,
  };

  // Function to create the widget
  function initWidget() {
    new SoyioWidget(widgetConfig);
  }

  // Add event listener to the button to create the widget on click
  document
    .getElementById("start-signature-attempt")
    .addEventListener("click", initWidget);
</script>

Optional props:

  • customColor.

Signature Attempt Events

  • IDENTITY_SIGNATURE: This event occurs when a user successfully completes a signature attempt. The event object includes:

    • eventName: The name of the event, in this case, 'IDENTITY_SIGNATURE'.
    • userReference: The reference identifier for the user, facilitating the association of the event with the user within the company's context.
  • REJECTED_SIGNATURE: Event triggered when user clicks the "reject" button in the signature attempt. The event object includes:

    • identityId: The unique identifier for the identity.
    • userReference: The userReference used in the validation attempt for the identity.

Signature Attempt Attribute Descriptions

  • signatureAttemptId: Identifier of signature attempt obtained when creating the SignatureAttempt. It must start with 'sa_'.
  • isSandbox: Indicates if the widget should operate in sandbox mode, defaulting to false.
  • onEvent: A callback function triggered upon event occurrences, used for capturing and logging event-related data.
  • customColor: A hex code string that specifies the base color of the interface.

Auth Request

📖 Integration Guide

The auth_request is a process where, using a previously created auth_request_id, a request is initiated in which a user can authenticate. This authentication can occur either through an access key or facial video. It's important to note that for this request, the user must have been previously verified with Soyio.

<button id="start-auth-request">Start auth request</button>

<script>
  import { SoyioWidget } from "@soyio/soyio-widget";

  // Widget configuration
  const widgetConfig = {
    request: "authentication_request",
    configProps: {
      authRequestId: "<auth request id>",
      customColor: "<custom color>",
    },
    onEvent: (data) => console.log(data),
    isSandbox: true,
  };

  // Function to create the widget
  function initWidget() {
    new SoyioWidget(widgetConfig);
  }

  // Add event listener to the button to create the widget on click
  document
    .getElementById("start-auth-request")
    .addEventListener("click", initWidget);
</script>

Optional props:

  • customColor.

Auth Request Attribute Descriptions

  • authRequestId: Identifier of auth request obtained when creating the AuthRequest. It must start with 'authreq_'.
  • isSandbox: Indicates if the widget should operate in sandbox mode, defaulting to false.
  • onEvent: A callback function triggered upon event occurrences, used for capturing and logging event-related data.
  • customColor: A hex code string that specifies the base color of the interface.

Appearance

Customize the look and feel of Soyio UI components by passing an appearance object to the configuration. The appearance object supports themes, CSS variables, and CSS rules for granular control over the styling.

Structure

The appearance object consists of four main sections:

const appearance = {
  theme: string,
  variables: Variables,
  rules: Rules,
  config: Config,
};

Themes

Built-in themes provide pre-configured color palettes and component styles:

| Theme | Description | | ----- | ----------- | | "soyio" | Default light theme with Soyio brand colors (purple/indigo), uppercase titles | | "night" | Dark mode theme with deep blues, muted colors, and subtle borders | | "flat" | Minimal theme with square corners, normal-case titles, thicker borders |

Theme style differences:

  • soyio: Standard styling with rounded corners and uppercase card titles
  • night: Dark backgrounds, lighter text, borders using theme variables
  • flat: No border radius, sentence-case titles (no uppercase), 2px borders, lighter font weights

Example:

const appearance = {
  theme: "night", // Use the dark theme
  variables: {
    // You can still override specific variables
    colorPrimary: "#FF6B6B",
  },
  rules: {
    // You can also override theme rules
    ".CardTitle": { fontWeight: "700" },
  },
};

Theme variables and rules are applied first, then your custom overrides take precedence.

Config

The config object allows you to adjust component behavior settings.

interface Config {
  helperTextPosition?: 'top' | 'bottom';
  hintIcon?: string;
  icon?: {
    weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone';
    size?: number;
  };
  iconRules?: Record<string, { weight?: IconWeight; size?: number }>;
  mainPageColumns?: 1 | 2 | 3 | 4;
  brandTheme?: 'default' | 'dark' | 'light';
}

| Property | Description | Default | | -------- | ----------- | ------- | | helperTextPosition | Position of helper/description text relative to form inputs | "bottom" | | hintIcon | Icon name for hint/help tooltips on input labels (see available icons below) | "Question" | | icon.weight | Global icon weight/style variant (see below) | "regular" | | icon.size | Global default icon size in pixels | 24 | | iconRules | Per-component icon style overrides | {} | | mainPageColumns | Number of columns in the main page feature cards grid (1-4) | 2 | | consentManagementColumns | Number of columns in the consent management grid (1-4) | 2 | | brandTheme | Theme variant for branded elements like the footer (default, dark, light) | "default" |

Icons

Soyio uses Phosphor Icons, a flexible icon family with multiple weight variants. You can customize the icon appearance globally using the config.icon settings, or override icons for specific components using config.iconRules.

Available icon weights:

| Weight | Description | | ------ | ----------- | | thin | Thinnest stroke width | | light | Light stroke width | | regular | Default stroke width | | bold | Bold stroke width | | fill | Filled/solid icons | | duotone | Two-tone icons with opacity |

Global icon example:

const appearance = {
  config: {
    icon: {
      weight: "bold",
      size: 20,
    },
  },
};

Per-component icon overrides:

Use iconRules to customize icons for specific components. The key is the component name (e.g., Alert, Switch) or a variant-specific key (e.g., Alert.error):

Note: For variant-specific icon rules, use dot notation (Alert.error) rather than the CSS double-dash syntax (Alert--error).

const appearance = {
  config: {
    icon: {
      weight: "regular", // Global default
    },
    iconRules: {
      Alert: { weight: "fill" },           // All alerts use filled icons
      Switch: { weight: "bold", size: 16 }, // Switch icons are bold and smaller
      "Alert.error": { weight: "fill" },    // Error alerts specifically
    },
  },
};

Hint icon customization:

The hint icon appears next to input labels when a tooltip/hint is available. You can change which icon is displayed using hintIcon:

| Icon Name | Description | | --------- | ----------- | | Question | Question mark in circle (default) | | Info | Information "i" icon | | QuestionMark | Simple question mark | | Warning | Warning/exclamation icon |

const appearance = {
  config: {
    hintIcon: "Info", // Use info icon instead of question mark
  },
};

You can also style the hint icon using the .HintIcon rule (see Supported rules).

Variables

Use variables to adjust common visual attributes across all components.

interface Variables {
  fontFamily?: string;
  fontFamilyBody?: string;
  fontFamilyTitle?: string;
  fontSizeBase?: string;
  colorPrimary?: string;
  colorPrimarySurface?: string;
  colorSecondary?: string;
  colorBackground?: string;
  colorSurface?: string;
  colorSurfaceMuted?: string;
  colorSurfaceStrong?: string;
  colorBorder?: string;
  colorBorderMuted?: string;
  colorSwitchBorder?: string;
  colorText?: string;
  colorTextSecondary?: string;
  colorTextSubtle?: string;
  colorTextInverted?: string;
  colorTextTitle?: string;
  colorLink?: string;
  colorInputFocus?: string;
  colorInputErrorFocus?: string;
  colorSelectArrow?: string;
  colorInfo?: string;
  colorInfoBg?: string;
  colorSuccess?: string;
  colorSuccessBg?: string;
  colorWarning?: string;
  colorWarningBg?: string;
  colorDanger?: string;
  colorDangerBg?: string;
  colorOverlay?: string;
  borderRadius?: string;
  borderWidth?: string;
  borderStyle?: string;
}

Available Variables

| Variable | Description | Default | | ----------------- | ---------------------------------------- | ------------------------- | | fontFamily | Base font stack (fallback for body and title) | "system-ui, sans-serif" | | fontFamilyBody | Font stack for body/paragraph text (falls back to fontFamily) | var(--fontFamily) | | fontFamilyTitle | Font stack for titles and headings (falls back to fontFamily) | var(--fontFamily) | | fontSizeBase | Base font size for text | "1rem" | | colorPrimary | Primary color for interactive elements | "#0570DE" | | colorPrimarySurface | Background color for primary elements (e.g. active tab) | "#EEF2FF" | | colorSecondary | Secondary color for interactive elements | "#A180F0" | | colorBackground | Background color | "#FFFFFF" | | colorSurface | Surface color for cards and sections | "#F9FAFB" | | colorSurfaceMuted | Muted surface color | "#F3F4F6" | | colorSurfaceStrong | Strong surface color | "#E5E7EB" | | colorBorder | Border color | "#D1D5DB" | | colorBorderMuted | Muted border color | "#E5E7EB" | | colorSwitchBorder | Border color for Switch component (unchecked) | "#000000" | | colorText | Main text color | "#1E1B4B" | | colorTextSecondary | Secondary text color | "#6B7280" | | colorTextSubtle | Subtle text color | "#9CA3AF" | | colorTextInverted | Inverted text color | "#FFFFFF" | | colorTextTitle | Title/heading text color (falls back to colorText) | var(--colorText) | | colorLink | Color for link elements | "#0570DE" | | colorInputFocus | Focus border/ring color for input elements | "#0570DE" | | colorInputErrorFocus| Focus border/ring color for input elements in error state | "#EF4444" | | colorSelectArrow | Color for select dropdown arrow icon | "#6B7280" | | colorInfo | Info status color | "#1E40AF" | | colorInfoBg | Info status background color | "#E0E7FF" | | colorSuccess | Success status color | "#15803D" | | colorSuccessBg | Success status background color | "#DCFCE7" | | colorWarning | Warning status color | "#B45309" | | colorWarningBg | Warning status background color | "#FEF3C7" | | colorDanger | Danger status color | "#EF4444" | | colorDangerBg | Danger status background color | "#FEF2F2" | | colorOverlay | Overlay color | "rgba(0, 0, 0, 0.5)" | | borderRadius | Base border radius (scales proportionally for different sizes) | "0.25rem" | | borderWidth | Border width for elements | "1px" | | borderStyle | Border style for elements | "solid" |

Note on Border Radius: The borderRadius variable serves as a base unit. Larger components (like Inputs and Buttons) use a multiple of this value (typically 2x), while smaller elements use a fraction or the base value itself. This ensures consistent scaling across all UI elements.

Rules

The rules object allows you to apply custom CSS to specific elements. Soyio supports styling for various components including inputs, buttons, switches, and more.

Supported rules

The rules are grouped by component category. Most rules support pseudo-classes and pseudo-elements that can be appended to style different states:

Supported pseudo-classes:

  • :hover - When the element is hovered
  • :focus - When the element is focused
  • :active - When the element is active/pressed
  • :disabled - When the element is disabled
  • :autofill - When the input is autofilled
  • :focus-visible - When focused via keyboard navigation

Supported pseudo-elements:

  • ::placeholder - Placeholder text in inputs
  • ::selection - Selected text

Example usage:

rules: {
  ".Button": { backgroundColor: "blue" },           // Base style
  ".Button:hover": { backgroundColor: "darkblue" }, // Hover state
  ".Button:disabled": { opacity: "0.5" },           // Disabled state
  ".Input::placeholder": { color: "gray" },         // Placeholder text
  ".RadioCard:hover": { borderColor: "var(--colorPrimary)" }, // Card hover
}
Layout
  • .MainContainer - The main container.
  • .Card - Card containers.
  • .CardTitle - Card title text.
  • .Dialog - Dialog containers.
  • .DialogOverlay - Dialog overlays.
  • .DialogContent - Dialog content areas.
Typography
  • .Title - Title text (base class for all titles).
  • .StepTitle - Step indicator title text (also inherits from .Title).
  • .Description - Description text.
Inputs
  • .Input - Input fields.
  • .Input--error - Input fields in error state.
  • .Label - Labels.
  • .HintIcon - Hint/help icons next to input labels.
  • .TextArea - Text area inputs.
  • .Select - Select dropdowns.
  • .Combobox - Combobox inputs.
  • .NinInput - Styles the input field for national identity numbers.
  • .TrackingCodeInput - Styles the tracking code input component.
  • .TrackingCodeInputCell - Styles individual cells in the tracking code input.
  • .TrackingCodeInputSeparator - Styles the separator between tracking code cells.
Buttons & Links
  • .Button - The button component.
  • .Link - Links.
Selection Controls

Checkbox Checkbox Appearance

  • .Checkbox - The checkbox container.
  • .CheckboxInput - The styled checkbox element (supports borderRadius, borderColor, backgroundColor).
  • .CheckboxLabel - The checkbox label.
  • .CheckboxCheck - The checkmark icon inside the checkbox.
  • .CheckboxInput--checked - The checked state of the checkbox.

Radio

  • .Radio - Radio button containers.
  • .RadioButton - The radio button element (the clickable circle).
  • .RadioButton--checked - Checked state of the radio button.
  • .RadioIndicator - The inner indicator point of the radio button.
  • .RadioIndicator--checked - Checked state of the radio indicator (visible when selected).
  • .RadioLabel - Radio button labels.

Switch

  • .Switch - Switch toggles (wrapper).
  • .SwitchRoot - Switch control (track).
  • .SwitchThumb - Switch thumb (circle).
  • .SwitchIcon - Switch icons (check/cross).
  • .SwitchRoot--checked - Checked state of the switch track
  • .SwitchThumb--checked - Checked state of the switch thumb

Radio Card

  • .RadioCard - Styles the wrapper card element of a radio card item.
  • .RadioCard--checked - Checked state of the radio card.
  • .RadioCardButton - The radio button element inside a radio card.
  • .RadioCardButton--checked - Checked state of the radio card button.
  • .RadioCardIndicator - The inner indicator point inside a radio card.
  • .RadioCardIndicator--checked - Checked state of the radio card indicator.
  • .RadioCardTitle - The title text inside a radio card (also inherits from .CardTitle).

Note: .RadioCardTitle elements also have the .CardTitle class, so you can style all card titles together with .CardTitle and override specifically for radio cards with .RadioCardTitle.

Step Indicator

The step indicator shows progress through multi-step forms.

  • .StepIndicatorContainer - The container wrapping all step indicators.
  • .StepIndicator - Individual step indicator item.
  • .StepIndicator--active - The currently active step.
  • .StepIndicator--completed - Steps that have been completed.
  • .StepIndicator--pending - Steps that are not yet reached.
  • .StepIndicatorLine - The connecting line between steps.
  • .StepIndicatorLine--top - The line segment above a step indicator.
  • .StepIndicatorLine--bottom - The line segment below a step indicator.
  • .StepIndicatorIcon - Icon displayed inside a step indicator (for completed steps).
  • .StepIndicatorDot - The dot marker in a step indicator.
  • .StepIndicatorNumber - The step number displayed in the indicator.
Feedback
  • .Loader - Loading indicators.
  • .ErrorMessage - Error message text.
  • .TooltipContent - Styles the content popover of a tooltip.

Alert

  • .Alert - Alert boxes.
  • .Alert--error - Error alert variant.
  • .Alert--warning - Warning alert variant.
  • .Alert--info - Information alert variant.
  • .Alert--success - Success alert variant.
  • .AlertIcon - The icon inside an alert.
  • .AlertContent - The content/text area inside an alert.

Chip

  • .Chip - Chips/Tags.
  • .Chip--info - Info chip variant.
  • .Chip--green - Green chip variant.
  • .Chip--red - Red chip variant.
  • .Chip--amber - Amber chip variant.
Consent Components

The following rules are specific to the Consent Box widget and allow customization of consent-related UI elements:

  • .CategoryTag - Data use category identifier (e.g., "Compartir datos con terceros"). Appears above category descriptions in expanded consent views.
  • .Badge - Optional/required label badge appearing on consent items.

Note: These consent-specific rules are only available in the ConsentBox widget and will have no effect in other widgets like PrivacyCenterBox.

Example Configuration

const appearance = {
  theme: "soyio",
  variables: {
    fontFamily: "system-ui, sans-serif",
    colorPrimary: "#f54c27",
    colorSecondary: "#f54c27",
    colorBackground: "#ffffff",
    colorText: "#1E1B4B",
    borderRadius: "0.5rem",
    borderWidth: "3px",
    borderStyle: "dashed",
  },
  rules: {
    ".MainContainer": {
      borderWidth: "1px",
      borderColor: "#E5E7EB",
      borderRadius: "0.25rem",
    },
    ".CheckboxInput": {
      appearance: "none",
      backgroundColor: "transparent",
      cursor: "pointer",
      width: "1rem",
      height: "1rem",
      borderRadius: "9999px",
      borderWidth: "2px",
      borderStyle: "solid",
      borderColor: "var(--colorPrimary)",
    },
    ".CheckboxInput--checked": {
      borderColor: "var(--colorPrimary)",
      backgroundColor: "var(--colorPrimary)",
    },
    ".CheckboxInput:hover": {
      borderColor: "var(--colorPrimary)",
      boxShadow: "0 0 0 2px var(--colorPrimary)",
    },
    ".CheckboxInput:focus": {
      outline: "none",
      boxShadow: "0 0 0 2px var(--colorPrimary)",
    },
    ".CheckboxInput:focus-visible": {
      outline: "none",
      boxShadow: "0 0 0 2px var(--colorPrimary)",
    },
    ".SwitchRoot": {
      backgroundColor: "#e5e7eb",
      borderRadius: "9999px",
      boxShadow: "none", // Remove default shadow
    },
    ".SwitchRoot--checked": {
      backgroundColor: "var(--colorPrimary)",
    },
    ".SwitchThumb": {
      backgroundColor: "white",
      borderRadius: "9999px",
      boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
    },
    ".SwitchIcon": {
      display: "none", // Hide the check/cross icons
    },
  },
  config: {
    helperTextPosition: "top", // Position helper text above inputs
  },
};

TypeScript

The SoyioTypes module from the @soyio/soyio-widget package provides TypeScript type definitions that you can use to integrate the SoyioWidget more seamlessly into your TypeScript projects.

To use the SoyioTypes in your project, import it directly from the @soyio/soyio-widget package:

import type { SoyioTypes } from "@soyio/soyio-widget";

JSON Schema Validation

The package includes JSON Schemas for validating configuration objects. This is useful for:

  • IDE Autocomplete: Get IntelliSense in your editor when writing configurations
  • Runtime Validation: Validate user-provided configurations before passing to the widget
  • Documentation: Use schemas to generate API documentation

Available Schemas

Appearance Schema

Validates appearance customization objects (theme, variables, rules, config):

// Import the schema
import appearanceSchema from "@soyio/soyio-widget/schemas/appearance";

// Use with a validator like Ajv
import Ajv from "ajv";
const ajv = new Ajv();
const validate = ajv.compile(appearanceSchema);

const appearance = {
  theme: "night",
  variables: {
    colorPrimary: "#007bff",
    borderRadius: "8px"
  }
};

if (validate(appearance)) {
  console.log("✅ Valid appearance config");
} else {
  console.error("❌ Invalid:", validate.errors);
}

Config Schema

Validates complete widget configuration including Privacy Center and Consent Box options:

import configSchema from "@soyio/soyio-widget/schemas/config";

const validate = ajv.compile(configSchema);
const config = {
  companyId: "com_example",
  appearance: { /* ... */ },
  onEvent: (event) => console.log(event)
};

if (validate(config)) {
  const privacyCenter = new PrivacyCenterBox(config);
  privacyCenter.mount("#container");
}

Using Schemas with Monaco Editor

Perfect for building configuration editors:

import * as monaco from "monaco-editor";
import configSchema from "@soyio/soyio-widget/schemas/config";

monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
  validate: true,
  schemas: [{
    uri: "https://soyio.id/widget-config.json",
    fileMatch: ["*"],
    schema: configSchema
  }]
});

Server Side Rendering (SSR)

This package is not directly compatible with SSR because of post-robot, but there are workarounds that allow you to use it without disrupting the build process. Below are examples on popular SSR frameworks.

Next.js

'use client'

import { useMemo, useEffect, useState } from "react";

export default function PrivacyCenterBox() {
	const privacyCenterOptions = useMemo(() => ({
		companyId: 'com_lalala',
		// ... other options
		onEvent: () => {}
	}), []);

	const [privacyCenter, setPrivacyCenter] = useState(null);

	useEffect(() => {
		async function mountPrivacyCenter() {
			if (privacyCenter) return;

			const { PrivacyCenterBox } = await import('@soyio/soyio-widget');
			const privacyCenterBox = new PrivacyCenterBox(privacyCenterOptions);
			privacyCenterBox.mount("#privacy-center-box");

			setPrivacyCenter(privacyCenterBox);
		}
		mountPrivacyCenter();

		return () => privacyCenter?.unmount();
	}, [privacyCenterOptions, privacyCenter]);

	return (
		<div>
			<h1>Hello World</h1>
			<div id="privacy-center-box"></div>
		</div>
	);
}

Gatsby

// PrivacyCenterBox.tsx

import React, { useEffect, useState, useMemo } from "react";

export default function PrivacyCenterBox({ onReady }) {
	const [privacyCenter, setPrivacyCenter] = useState(null);

	const privacyCenterOptions = useMemo(() => ({
		// other options...
		companyId: process.env.SOYIO_COMPANY_ID || 'com_lalala',
		onEvent: () => {}
	}), [onReady]);

	useEffect(() => {
		async function mountPrivacyCenter() {
			if (privacyCenter) return;

			const { PrivacyCenterBox } = await import('@soyio/soyio-widget');
			const privacyCenterBox = new PrivacyCenterBox(privacyCenterOptions);
			privacyCenterBox.mount("#privacy-center-box");

			setPrivacyCenter(privacyCenterBox);
		}
		mountPrivacyCenter();

		return () => privacyCenter?.unmount();
	}, [privacyCenterOptions, privacyCenter]);

	return (<div id="privacy-center-box"></div>)
}

Then use React.lazy and React.Suspense when declaring that component elsewhere.

// AnotherComponent.tsx

import React, { useState, useCallback, useEffect } from "react";

const PrivacyCenterBox = React.lazy(() => import('yourPathTo/PrivacyCenterBox'));

export default function PrivacyCenterContainer() {
	const [isClient, setIsClient] = useState(false);

	useEffect(() => setIsClient(true), []);

	const onReady = useCallback(() => setIsPrivacyCenterLoading(false), []);

	return (
		<div>
		  {isClient &&
		  <React.Suspense fallback={
			<div>
				Loading...
			</div>
		  }>
			<PrivacyCenterBox onReady={onReady} />
		  </React.Suspense>
		  }
		</div>
	)
}

Development

To run the widget customization smoke test locally:

yarn run smoke

The smoke test configuration is loaded from smoke-test/.env.development. You can modify this file to change the default values:

VITE_COMPANY_ID=com_test
VITE_PRIVACY_CENTER_URL=http://localhost:5173
VITE_CONSENT_URL=http://localhost:5173
VITE_CONSENT_TEMPLATE_ID=constpl_test

To test DSR rights in the Privacy Center tab, add these parameters to the JSON config in the editor:

{
  "enabledRights": ["arsop", "redec"],
  "redecOperationIds": [
    { "id": "op_update", "label": "Update" },
    { "id": "op_rectification", "label": "Rectification" }
  ]
}

redecOperationIds is required when redec is included in enabledRights.

Presets Management

The smoke test includes preset management functionality that allows you to save, load, and share widget configurations:

  • Save Presets: Save your current widget configuration with a custom name
  • Load Presets: Quickly switch between saved configurations
  • Export Presets: Download all presets as a JSON file for backup or sharing
  • Import Presets: Load presets from a previously exported JSON file

All presets are automatically saved to your browser's localStorage. Use the export feature to persist presets to disk and share them with your team. See smoke-test/PRESETS.md for detailed documentation.