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

@unvired/turboforms-embed-sdk

v1.0.20

Published

Reusable vanilla JS form library that works with React, Angular, Ionic, etc.

Downloads

852

Readme

Unvired Forms SDK

A powerful, lightweight JavaScript SDK for rendering dynamic forms with advanced features like geolocation, camera integration, barcode scanning, and file uploads. Built on Form.io JSON schema, this SDK works seamlessly across all modern web frameworks and mobile platforms.

🌟 Features

  • Universal Compatibility: Works with React.js, Angular, Ionic, Cordova, and vanilla JavaScript
  • Advanced Components: Built-in support for geolocation, camera, barcode scanning, and file attachments
  • Form.io Integration: Renders Form.io JSON schema-based forms with full feature support
  • Cross-Platform: Seamless integration across web and mobile applications
  • Event-Driven: Robust event callback system for form interactions
  • TypeScript Support: Full TypeScript definitions included

📦 Installation

npm install unvired-forms-sdk

🚀 Usage Examples

Vanilla JavaScript

<!DOCTYPE html>
<html>
<head>
    <title>Unvired Forms Integration</title>
</head>
<body>
    <div id="form-container"></div>
    
    <script type="module">
        import { loadUnviredForms } from './dist/unvired-forms-sdk.js';
        
        const formInstance = loadUnviredForms({
            formsData: formTemplateData,
            submissionData: preFillData || {},
            eventCallback: function (event) {
                console.log('Form event:', event);
                
                switch (event.type) {
                    case 'FORM_SUBMIT':
                        console.log('Form submitted:', event.data);
                        break;
                    case 'FORM_BACK_NAVIGATION':
                        window.history.back();
                        break;
                }
            },
            container: document.getElementById('form-container'),
            options: {
                formioLibPath: {
                    formioPath: "./dist/assets/formio.full.min.js",
                    lessFilesPath: "./dist/assets/fomantic-ui/definitions"
                },
                mode: "render",
                platform: "web",
                showBackButton: true,
                userData: {
                    user: "John Doe",
                    email: "[email protected]"
                }
            }
        });
    </script>
</body>
</html>

React.js Integration

import React, { useRef, useEffect } from 'react';
import { loadUnviredForms } from 'unvired-forms-sdk';

const UnviredForm = ({ formData, onSubmit, onBack }) => {
    const containerRef = useRef(null);
    const formInstanceRef = useRef(null);
    
    useEffect(() => {
        if (containerRef.current && formData) {
            formInstanceRef.current = loadUnviredForms({
                formsData: formData,
                submissionData: {},
                eventCallback: (event) => {
                    switch (event.type) {
                        case 'FORM_SUBMIT':
                            onSubmit?.(event.data);
                            break;
                        case 'FORM_BACK_NAVIGATION':
                            onBack?.();
                            break;
                    }
                },
                container: containerRef.current,
                options: {
                    formioLibPath: {
                        formioPath: "./assets/formio.full.min.js",
                        lessFilesPath: "./assets/fomantic-ui/definitions"
                    },
                    mode: "render",
                    platform: "web",
                    showBackButton: true
                }
            });
        }
        
        return () => {
            // Cleanup if needed
        };
    }, [formData, onSubmit, onBack]);
    
    return <div ref={containerRef} style={{ width: '100%', height: '100%' }} />;
};

export default UnviredForm;

Angular Integration

import { Component, ElementRef, ViewChild, Input, Output, EventEmitter } from '@angular/core';
import { loadUnviredForms, FormEvent } from 'unvired-forms-sdk';

@Component({
  selector: 'app-unvired-form',
  template: '<div #formContainer style="width: 100%; height: 100%;"></div>'
})
export class UnviredFormComponent {
  @ViewChild('formContainer', { static: true }) formContainer!: ElementRef;
  @Input() formData: any;
  @Output() formSubmit = new EventEmitter<any>();
  @Output() formBack = new EventEmitter<void>();
  
  ngOnInit() {
    if (this.formData) {
      loadUnviredForms({
        formsData: this.formData,
        submissionData: {},
        eventCallback: (event: FormEvent) => {
          switch (event.type) {
            case 'FORM_SUBMIT':
              this.formSubmit.emit(event.data);
              break;
            case 'FORM_BACK_NAVIGATION':
              this.formBack.emit();
              break;
          }
        },
        container: this.formContainer.nativeElement,
        options: {
          formioLibPath: {
            formioPath: "./assets/formio.full.min.js",
            lessFilesPath: "./assets/fomantic-ui/definitions"
          },
          mode: "render",
          platform: "web"
        }
      });
    }
  }
}

Cordova Integration

// In your Cordova app's main JavaScript file
document.addEventListener('deviceready', function() {
    import('./js/unvired-forms-sdk.js').then(({ loadUnviredForms }) => {
        const formInstance = loadUnviredForms({
            formsData: formTemplateData,
            submissionData: {},
            eventCallback: function (event) {
                switch (event.type) {
                    case 'FORM_SUBMIT':
                        console.log('Form submitted:', event.data);
                        break;
                    case 'OPEN_CAMERA':
                        handleCameraRequest(event.data);
                        break;
                    case 'LOCATION_REQUEST':
                        handleLocationRequest(event.data);
                        break;
                }
            },
            container: document.getElementById('form-container'),
            options: {
                formioLibPath: {
                    formioPath: "./js/formio.full.min.js",
                    lessFilesPath: "./css/fomantic-ui/definitions"
                },
                mode: "render",
                platform: "cordova",
                showBackButton: true
            }
        });
    });
}, false);

📋 API Reference

LoadUnviredFormsParams

| Property | Type | Required | Description | |----------|------|----------|-------------| | formsData | string | object | ✅ | Form.io JSON schema or JSON string | | submissionData | object | ❌ | Pre-filled form data | | eventCallback | function | ❌ | Event handler function | | container | HTMLElement | ❌ | DOM container element | | options | object | ❌ | Configuration options |

Options Configuration

| Property | Type | Description | |----------|------|-------------| | formioLibPath | object | FormIO library paths configuration | | nestedFormData | array | Nested form data | | masterData | array | Master data for dropdowns | | title | string | Form title | | description | string | Form description | | mode | string | Form mode: 'render', 'readOnly', 'print', 'pdf' | | platform | string | Platform: 'web', 'android', 'ios', 'cordova' | | language | string | Language code | | translations | object | Translation strings | | themeData | object | Custom theme configuration | | showBackButton | boolean | Show/hide back navigation | | showMoreButton | boolean | Show/hide more options menu | | userData | object | User context data | | appData | object | Application data | | environmentVariable | array | Environment variables | | privateExternal | boolean/string | Controls form visibility logic (Private/Public) | | permission | string | Access permission ('writesingle', 'writemultiple', 'read') | | controlData | object | Data for initial control values | | showLoader | boolean | Show/hide initial SDK loading spinner |

Event Types

| Event | Description | |-------|-------------| | FORM_RENDER | Form rendered successfully | | FORM_SUBMIT | Form submission completed | | FORM_SAVE | Form data saved | | FORM_BACK_NAVIGATION | Back button pressed | | FORM_ONCHANGE | Form field value changed | | OPEN_CAMERA | Camera access requested | | LOCATION_REQUEST | Location access requested | | BARCODE_SCAN | Barcode scanning completed | | GET_ATTACHMENT | Attachment request | | ERROR | Error occurred |

✅ Button Visibility & Enablement

| privateExternal | Permission | Main Toolbar Button | More Options (Dropdown) | Enable / Disable Rule | | ------------------ | --------------- | -------------------------- | ------------------------------- | -------------------------------------------------- | | false (Public) | writesingle | Submit (submitBtn) | None | Enabled when any field is filled | | false (Public) | writemultiple | Submit (submitBtn) | None | Enabled when any field is filled | | true (Private) | writemultiple | Save (saveBtn) | Complete (completeOption) | Save enabled when any field is filled | | true (Private) | writesingle | Complete (submitBtn) | Save (saveOption) | Complete enabled ONLY when form is 100% filled | | Any | read | None | None | N/A (Read-only mode) |

🧭 “More Options” Dropdown Logic

Complete appears in More Options

  • Condition: privateExternal = true AND permission = writemultiple
  • Reason: Allows partial saves via main Save button Final submission (Complete) is optional and secondary

Save appears in More Options

  • Condition: privateExternal = true AND permission = writesingle
  • Reason: Forces 100% completion via main Complete button Save is available only as a fallback action

🔑 Core Behavioral Rules

  • Public forms → Always Submit, enabled after any input
  • Private + writemultipleSave first, Complete optional
  • Private + writesingleComplete mandatory, Save optional
  • Read permission → No actions shown

📂 File Attachment Architecture & Modes

The SDK employs a robust local-first strategy using IndexedDB for offline storage and persistence. To track the exact state of every file or image across its entire lifecycle (from server to local device to edits to deletion), the SDK uniquely assigns a synchronization mode to each file.

Mode Classification

| Mode | Name | Description | |---|---|---| | "A" | Added (New) | Represents a brand new file uploaded locally. Newly taken photos, selected files from the gallery, or newly cropped/edited images default to this state. | | "G" | Got (Downloaded) | Represents a file that previously existed and was downloaded from the server API. The API dictates this mode, and the SDK recognizes it. By default, any file reconstructed from IndexedDB that lacks a mode tag assumes "G". | | "D" | Deleted | Represents an attachment that was marked as deleted by the user clicking the trash icon. The system physically flags the file in the database rather than removing the row entirely, permitting the host app to notify the server of the deletion upon final sync. |

Working Flow: Cropping or Editing an Image

When a user crops or annotates an existing server image or local image, the SDK executes the following sequence:

  1. In-Memory Capture: The crop/annotation tool creates a brand new physical Blob containing the updated image metadata safely in RAM.
  2. New DB Entry Created: The SDK assigns a fresh UUID to the newly cropped image and stores it inside the IndexedDB as a completely individual brand new file with mode: "A".
  3. Original File Deleted: To preserve device storage and state integrity, the SDK locates the original file's UUID corresponding to the un-cropped image and physically deletes it out of the IndexedDB via a deleteOriginalFileFromDB listener event.
  4. Memory Re-linking: The form component's memory immediately reflects the presence of the new file object bearing mode "A" substituted into the form submission pipeline.

This process simplifies the architecture: edits simply generate brand new files, offloading any complex diffing logic to the main application server layer.

⚡ Performance Optimization

Pre-initializing SmartStorage (IndexedDB)

Opening an IndexedDB connection can sometimes introduce a slight delay (lag) during the first file upload or image capture. To eliminate this, the SDK dispatches a smartStorageReady event as soon as the storage provider is registered.

You can listen for this event in your host application and call preInitialize() to "warm up" the database connection immediately during page load, ensuring the first upload is instantaneous.

Implementation Example

// Proper event-driven initialization in your host application
(function() {
    const initDb = (SmartStorage) => {
        if (SmartStorage && typeof SmartStorage.preInitialize === 'function') {
            console.log("⚡ Pre-initializing SmartStorage IndexedDB...");
            SmartStorage.preInitialize();
        }
    };

    // 1. Check if already loaded in Formio provider registry
    const existing = window.Formio?.providers?.storage?.SmartStorage || 
                   window.Formio?.Providers?.providers?.storage?.SmartStorage;
    
    if (existing) {
        initDb(existing);
    } else {
        // 2. Otherwise listen for the SDK's "ready" event dispatched on document
        document.addEventListener('smartStorageReady', (e) => {
            initDb(e.detail.SmartStorage);
        }, { once: true });
    }
})();

🔧 Form Instance Methods

The loadUnviredForms function returns a FormInstance object with the following methods:

const formInstance = loadUnviredForms(params);

// Send actions to the form
formInstance.sendAction({
    type: "SET_IMAGE_DATA",
    imageData: base64ImageData,
    controlId: "photo_field"
});

// Get attachments (if available)
if (formInstance.getAttachments) {
    const attachments = await formInstance.getAttachments();
    console.log('Form attachments:', attachments);
}

// Clear attachments (if available)
if (formInstance.clearAttachments) {
    const success = await formInstance.clearAttachments();
    console.log('Attachments cleared:', success);
}

// Validate attachments (if available)
if (formInstance.validateAttachments) {
    formInstance.validateAttachments(formData);
}

// Delete specific attachment (if available)
if (formInstance.deleteAttachment) {
    const success = await formInstance.deleteAttachment('fileId');
    console.log('Attachment deleted:', success);
}

Action Types

// Set image data for camera controls
formInstance.sendAction({
    type: "SET_IMAGE_DATA",
    imageData: "data:image/jpeg;base64,...",
    controlId: "camera_field_id"
});

// Set barcode scan result
formInstance.sendAction({
    type: "SET_BARCODE_DATA",
    scannedValue: "123456789",
    controlId: "barcode_field_id"
});

// Set location data
formInstance.sendAction({
    type: "SET_LOCATION_DATA",
    location: "40.7128,-74.0060",
    coordinates: { lat: 40.7128, lng: -74.0060 },
    controlId: "location_field_id"
});

🛠 Error Handling

The SDK provides comprehensive error handling with specific error codes:

loadUnviredForms({
    // ... other params
    eventCallback: function(event) {
        if (event.type === 'ERROR') {
            switch (event.errorMessage) {
                case 'Error Code 001 contact your admin or tech team':
                    console.error('Invalid formsData JSON');
                    break;
                case 'Error Code 004 contact your admin':
                    console.error('User Data not Provided');
                    break;
                case 'Error Code 013 contact your admin or tech team':
                    console.error('Attachments missing from storage');
                    break;
                // Handle other error codes...
            }
        }
    }
});

Error Codes Reference

| Code | Description | |------|-------------| | 001 | Invalid formsData JSON | | 002 | Nested form validation error | | 003 | Master data validation error | | 004 | User Data not Provided | | 005 | Form render error | | 006 | Form submit error | | 007 | Form complete error | | 008 | Location permission denied | | 009 | Location unavailable | | 010 | Location request timeout | | 011 | Location unknown error | | 012 | Camera access error | | 013 | Attachments missing from storage | | 014 | Failed to validate attachments | | 015 | File not found in IndexedDB |

🔐 Security Considerations

  • Validate all form data before processing
  • Implement proper file upload restrictions
  • Use HTTPS in production environments
  • Sanitize user inputs to prevent XSS attacks

🧪 Platform Compatibility

| Platform | Version | Status | |----------|---------|--------| | React.js | 16.8+ | ✅ Fully Supported | | Angular | 12+ | ✅ Fully Supported | | Vue.js | 3.0+ | ✅ Fully Supported | | Ionic | 5+ | ✅ Fully Supported | | Cordova | 9+ | ✅ Fully Supported | | Vanilla JS | ES6+ | ✅ Fully Supported |

🛠 Build Process

Development Setup

  1. Install dependencies

    npm install
  2. Build for web platforms

    npm run build
  3. Build for Flutter (optional)

    npm run build:flutter

Build Scripts

  • npm run build - Executes node scripts/build.js for standard web build
  • npm run build:flutter - Executes node scripts/build-flutter.js for Flutter-specific build

Build Output

The build process generates:

  • dist/unvired-forms-sdk.js - Main SDK bundle
  • dist/index.d.ts - TypeScript definitions
  • dist/assets/ - FormIO library and UI assets

📝 License