New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@soyio/soyio-widget

Package Overview
Dependencies
Maintainers
4
Versions
136
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@soyio/soyio-widget

Soyio Widget

latest
Source
npmnpm
Version
3.2.0
Version published
Weekly downloads
471
423.33%
Maintainers
4
Weekly downloads
 
Created
Source

Soyio Widget

Our SDK for web based integrations

NPM - Version

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

📖 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
    allowGranularScopeSelection: true, // Optional
    metadata: { key: "value" }, // 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>

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.

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

  • 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.

  • allowGranularScopeSelection: Enables selecting consent at a more granular scope when the template supports granular scopes.

  • metadata: An optional object with arbitrary metadata to attach to the consent. This metadata will be included in the consent record. The object must be serializable to JSON; properties with non-serializable values (like functions or undefined) will be omitted.

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" },
    ],

    // Override the "exercise your rights" link shown in consent-only mode (optional)
    externalRightsExerciseUrl: "https://privacy.example.com/rights",

    // Header and copy customization (optional)
    content: {
      header: {
        title: "Privacy preferences",
        description: "Manage your requests and consent settings.",
      },
      consentManagement: {
        header: {
          title: "Manage your consent settings",
          description: "Select which permissions should remain active.",
        },
      },
      rightExamples: {
        access: 'Example: "I want to know what data you store about me."',
      },
    },

    // Consent management grouping customization (optional)
    consentManagement: {
      scopeGroups: [
        {
          title: "Financial products",
          scopes: [
            { scopeType: "product", scopeId: "prod_checking_account" },
            { scopeType: "product", scopeId: "prod_credit_card" },
          ],
        },
        {
          title: "Main branches",
          scopes: [
            { scopeType: "branch", scopeId: "branch_centro" },
            { scopeType: "branch", scopeId: "branch_providencia" },
          ],
        },
      ],
    },

    // Common options
    consentControl: "checkbox", // Optional: 'switch' (default) | 'checkbox'
    consentMode: "batch", // Optional: 'immediate' (default) | 'batch'
    showBatchConsentConfirmation: true, // Optional: only used in batch mode
    consentRetentionPeriod: "30 days", // Optional: prevents immediate revoke for this period
    allowGranularScopeSelection: true, // Optional: only applies when templates have multiple scopes
    groupConsentsByScope: true, // Optional: groups consent templates by scope in consent management
    onEvent: (event) => console.log(event),
    onReady: () => console.log("PrivacyCenterBox is ready"), // Optional
    isSandbox: true, // Optional
    appearance: {
      config: {
        showHeader: true,
        showConsentManagementHeader: true,
      },
    }, // 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.
  • externalRightsExerciseUrl: Optional URL used by required consent alerts when users need to exercise their rights outside the embedded privacy center.
  • appearance.config.showHeader: Optional boolean to show/hide the privacy center header (title and description).
  • content.header: Optional object with title and description overrides for the privacy center header copy.
  • appearance.config.showConsentManagementHeader: Optional boolean to show/hide the title and description in the consent management page.
  • content.consentManagement.header: Optional object with title and description overrides for the consent management header copy.
  • content.rightExamples: Optional object to override DSR right examples. Supported keys: access, opposition, rectification, suppression, portability, redec_update, redec_rectification, redec_complementation, redec_cancellation.
  • header: Optional legacy alias for content.header.
  • rightExamples: Optional legacy alias for content.rightExamples.
  • 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'.
  • allowGranularScopeSelection: Optional boolean, enables selecting/deselecting individual consent scopes in consent management when templates define multiple scopes. When enabled and a consent has more than one scope, the main consent checkbox supports partial state.
  • groupConsentsByScope: Optional boolean, groups consent templates by scope in consent management. This must be enabled for consentManagement.scopeGroups to apply.
  • consentManagement.scopeGroups: Optional array to customize accordion groups in consent management. Each group requires a title and a scopes array with { scopeType: 'product' | 'branch', scopeId: string } entries. Scopes not included in custom groups keep the default scope grouping.
  • 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.
  • consentManagement.scopeGroups is applied during initial iframe URL render and also synchronized through SET_PRIVACY_CENTER_CONFIG updates.
  • content.header, content.consentManagement.header, appearance.config.showConsentManagementHeader, and externalRightsExerciseUrl are applied through SET_PRIVACY_CENTER_CONFIG; those overrides may briefly appear after the iframe is ready.

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:

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

  • 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:

ThemeDescription
"soyio"Default light theme with Soyio brand colors (purple/indigo), uppercase titles
"flat"Minimal theme with square corners, normal-case titles, thicker borders
"neutral"Neutral palette that works well for both light and dark modes
"night"Deprecated alias for theme: "soyio" with mode: "dark"

Theme style differences:

  • soyio: Standard styling with rounded corners and uppercase card titles
  • flat: No border radius, sentence-case titles (no uppercase), 2px borders, lighter font weights
  • neutral: Balanced grayscale palette intended for a more subdued branded experience

Color Modes

Appearance now supports a mode field:

ModeDescription
"light"Forces light mode
"dark"Forces dark mode
"auto"Follows the user's system color scheme

Example:

const appearance = {
  theme: "soyio",
  mode: "dark",
  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.

theme: "night" is still accepted as a deprecated alias for backwards compatibility, but new integrations should use theme + mode.

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';
}
PropertyDescriptionDefault
helperTextPositionPosition of helper/description text relative to form inputs"bottom"
hintIconIcon name for hint/help tooltips on input labels (see available icons below)"Question"
icon.weightGlobal icon weight/style variant (see below)"regular"
icon.sizeGlobal default icon size in pixels24
iconRulesPer-component icon style overrides{}
mainPageColumnsNumber of columns in the main page feature cards grid (1-4)2
consentManagementColumnsNumber of columns in the consent management grid (1-4)2
brandThemeTheme 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:

WeightDescription
thinThinnest stroke width
lightLight stroke width
regularDefault stroke width
boldBold stroke width
fillFilled/solid icons
duotoneTwo-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 NameDescription
QuestionQuestion mark in circle (default)
InfoInformation "i" icon
QuestionMarkSimple question mark
WarningWarning/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

VariableDescriptionDefault
fontFamilyBase font stack (fallback for body and title)"system-ui, sans-serif"
fontFamilyBodyFont stack for body/paragraph text (falls back to fontFamily)var(--fontFamily)
fontFamilyTitleFont stack for titles and headings (falls back to fontFamily)var(--fontFamily)
fontSizeBaseBase font size for text"1rem"
colorPrimaryPrimary color for interactive elements"#0570DE"
colorPrimarySurfaceBackground color for primary elements (e.g. active tab)"#EEF2FF"
colorSecondarySecondary color for interactive elements"#A180F0"
colorBackgroundBackground color"#FFFFFF"
colorSurfaceSurface color for cards and sections"#F9FAFB"
colorSurfaceMutedMuted surface color"#F3F4F6"
colorSurfaceStrongStrong surface color"#E5E7EB"
colorBorderBorder color"#D1D5DB"
colorBorderMutedMuted border color"#E5E7EB"
colorSwitchBorderBorder color for Switch component (unchecked)"#000000"
colorTextMain text color"#1E1B4B"
colorTextSecondarySecondary text color"#6B7280"
colorTextSubtleSubtle text color"#9CA3AF"
colorTextInvertedInverted text color"#FFFFFF"
colorTextTitleTitle/heading text color (falls back to colorText)var(--colorText)
colorLinkColor for link elements"#0570DE"
colorInputFocusFocus border/ring color for input elements"#0570DE"
colorInputErrorFocusFocus border/ring color for input elements in error state"#EF4444"
colorSelectArrowColor for select dropdown arrow icon"#6B7280"
colorInfoInfo status color"#1E40AF"
colorInfoBgInfo status background color"#E0E7FF"
colorSuccessSuccess status color"#15803D"
colorSuccessBgSuccess status background color"#DCFCE7"
colorWarningWarning status color"#B45309"
colorWarningBgWarning status background color"#FEF3C7"
colorDangerDanger status color"#EF4444"
colorDangerBgDanger status background color"#FEF2F2"
colorOverlayOverlay color"rgba(0, 0, 0, 0.5)"
borderRadiusBase border radius (scales proportionally for different sizes)"0.25rem"
borderWidthBorder width for elements"1px"
borderStyleBorder 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.
  • .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.

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: "soyio",
  mode: "dark",
  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.

FAQs

Package last updated on 10 Apr 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts