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

@enerjisaformlibrary/formbuilder-react

v1.0.22

Published

Professional drag-and-drop form builder React component with 20+ field types, multi-step wizard, conditional logic, undo/redo, and JSON export

Readme

@enerjisaformlibrary/formbuilder-react

Professional drag-and-drop form builder React component with 20+ field types, multi-step wizard support, conditional logic, undo/redo history, and JSON export/import.

Features

  • 20+ Field Types: Text, textarea, number, email, phone, URL, password, date, time, date range, dropdown, checkbox, radio, toggle, multi-select, file upload, signature pad, star rating, slider, color picker, rich text editor, autocomplete, QR code, pattern format, and more
  • Drag & Drop: Intuitive drag-and-drop interface for building forms
  • Multi-Step Wizard: Create multi-step forms with progress indicator
  • Conditional Logic: Show/hide/enable/disable fields based on conditions
  • Undo/Redo: Full undo/redo support with 50-state history
  • Grid Layout: 12-column responsive grid system
  • Containers: Nested row/column layouts within containers
  • JSON Export/Import: Export forms as JSON and import them back
  • Custom Styling: Per-field CSS class customization
  • Form Versioning: Save and restore form versions
  • Tooltips: Help text support for fields
  • Actions System: onClick, onChange, onFocus, onBlur event handlers
  • Tab Index: Keyboard navigation order for form fields

Installation

npm install @enerjisaformlibrary/formbuilder-react

Quick Start

import { FormBuilder } from '@enerjisaformlibrary/formbuilder-react';
import '@enerjisaformlibrary/formbuilder-react/styles.css';

function App() {
  const handleSave = (formSchema) => {
    console.log('Form saved:', formSchema);
    // Save to your database
  };

  const handleChange = (formSchema) => {
    console.log('Form changed:', formSchema);
  };

  return (
    <FormBuilder
      onSave={handleSave}
      onChange={handleChange}
    />
  );
}

Props

| Prop | Type | Required | Description | |------|------|----------|-------------| | initialSchema | FormSchema | No | Initial form schema to load | | onSave | (schema: FormSchema) => void | No | Called when user clicks Save button | | onChange | (schema: FormSchema) => void | No | Called on every form change |

Form Schema Structure

interface FormSchema {
  id: string;
  name: string;
  description?: string;
  isMultiStep: boolean;
  currentVersion: number;
  rows: FormRow[];           // For single-page forms
  steps?: FormStep[];        // For multi-step forms
  settings?: FormSettings;
  submissionConfig?: SubmissionConfig;
  versions?: FormVersion[];
}

interface FormRow {
  id: string;
  columns: FormColumn[];
  conditionalLogic?: ConditionalLogic;
}

interface FormColumn {
  id: string;
  width: number;  // 1-12 (grid columns)
  fields: FormField[];
  responsiveWidth?: ResponsiveWidth;
}

interface FormField {
  id: string;
  type: FieldType;
  props: FieldProps;
  validation?: FieldValidation;
  conditionalLogic?: ConditionalLogic;
  customStyle?: CustomStyle;
}

Field Types

Basic Fields

  • input - Single line text input
  • textarea - Multi-line text area
  • number - Numeric input
  • email - Email input with validation
  • password - Password input
  • phone - Phone number input
  • url - URL input

Date & Time

  • date - Date picker
  • time - Time picker
  • daterange - Date range picker

Selection Fields

  • dropdown - Single select dropdown
  • checkbox - Checkbox field
  • radio - Radio button group
  • toggle - Toggle switch
  • multiselect - Multi-select with tags

Advanced Fields

  • file - File upload with drag-drop
  • signature - Signature pad with canvas drawing
  • rating - Star rating (configurable max stars)
  • slider - Range slider with min/max
  • color - Color picker with hex input
  • richtext - Rich text editor
  • autocomplete - Autocomplete input
  • pattern - Pattern format input (phone, credit card, etc.)
  • qrcode - Static QR code display

Static Elements

  • header - Section header
  • label - Static label text
  • paragraph - Paragraph text
  • divider - Horizontal divider
  • spacer - Vertical spacer
  • alert - Alert/notification box
  • image - Image placeholder
  • button - Submit/reset/custom action buttons

Structure

  • container - Grouping element with nested rows/columns

Field Props

interface FieldProps {
  key: string;              // Unique field key for form data
  label?: string;           // Field label
  placeholder?: string;     // Placeholder text
  tooltip?: string;         // Help tooltip text
  optionsString?: string;   // Options for dropdown/radio/checkbox (one per line)
  size?: 'small' | 'medium' | 'large';
  autoFocus?: boolean;
  tabIndex?: number;        // Keyboard navigation order (positive = order, -1 = skip, 0 = natural order)
  htmlAttributes?: Record<string, string>;
  
  // Button specific
  buttonConfig?: {
    buttonType: 'submit' | 'reset' | 'button';
    variant: 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive';
    actionType?: 'submit' | 'reset' | 'navigate' | 'custom';
    navigateUrl?: string;
    customAction?: string;
  };
  
  // Pattern format specific
  patternConfig?: {
    format: 'phone' | 'creditCard' | 'date' | 'ssn' | 'custom';
    mask?: string;
    customPattern?: string;
  };
  
  // QR Code specific
  qrCodeConfig?: {
    value: string;
    size: number;
  };
  
  // Container specific
  containerConfig?: {
    rows: ContainerRow[];
    gap?: number;
    padding?: number;
    borderStyle?: 'none' | 'solid' | 'dashed';
  };
  
  // Rating specific
  maxRating?: number;
  
  // Slider specific
  min?: number;
  max?: number;
  step?: number;
}

Tab Index Usage

The tabIndex property controls keyboard navigation order when users press Tab to move between form fields:

| Value | Behavior | |-------|----------| | Positive (1, 2, 3...) | Field is focused in order from lowest to highest tabIndex | | 0 | Field follows natural DOM order | | -1 | Field is skipped during Tab navigation |

Example: To create a custom tab order:

  • First Name: tabIndex = 1
  • Email: tabIndex = 2
  • Last Name: tabIndex = 3
  • Phone: tabIndex = 4

When user presses Tab, they'll move: First Name → Email → Last Name → Phone

Important: tabIndex only works in Preview Mode. In editor mode, fields don't receive focus in the same way.

Validation

interface FieldValidation {
  required?: boolean;
  minLength?: number;
  maxLength?: number;
  min?: number;
  max?: number;
  pattern?: string;
  customMessage?: string;
}

Conditional Logic

interface ConditionalLogic {
  enabled: boolean;
  action: 'show' | 'hide' | 'enable' | 'disable' | 'require';
  conditions: Condition[];
  logicOperator: 'and' | 'or';
}

interface Condition {
  fieldKey: string;
  operator: 'equals' | 'notEquals' | 'contains' | 'notContains' | 
            'greaterThan' | 'lessThan' | 'isEmpty' | 'isNotEmpty';
  value: string;
}

Custom Styling

interface CustomStyle {
  containerClassName?: string;  // CSS class for field container
  labelClassName?: string;      // CSS class for label
  inputClassName?: string;      // CSS class for input element
  css?: string;                 // Custom CSS (applied inline)
}

Actions System

Each field can have event handlers:

interface FieldActions {
  onClick?: FieldAction;
  onChange?: FieldAction;
  onFocus?: FieldAction;
  onBlur?: FieldAction;
}

interface FieldAction {
  type: 'showMessage' | 'hideField' | 'showField' | 'clearField' | 
        'setFieldValue' | 'focusField' | 'submitForm' | 'custom' | 'code';
  args?: {
    message?: string;
    targetFieldKey?: string;
    value?: string;
    code?: string;
  };
}

Multi-Step Forms

interface FormStep {
  id: string;
  title: string;
  description?: string;
  order: number;
  rows: FormRow[];
  validation?: {
    validateOnNext?: boolean;
    allowSkip?: boolean;
  };
}

Example: Complete Form Schema

{
  "id": "contact-form",
  "name": "Contact Form",
  "isMultiStep": false,
  "currentVersion": 1,
  "rows": [
    {
      "id": "row-1",
      "columns": [
        {
          "id": "col-1",
          "width": 6,
          "fields": [
            {
              "id": "field-1",
              "type": "input",
              "props": {
                "key": "firstName",
                "label": "First Name",
                "placeholder": "Enter your first name",
                "tabIndex": 1
              },
              "validation": {
                "required": true,
                "minLength": 2
              }
            }
          ]
        },
        {
          "id": "col-2",
          "width": 6,
          "fields": [
            {
              "id": "field-2",
              "type": "input",
              "props": {
                "key": "lastName",
                "label": "Last Name",
                "placeholder": "Enter your last name",
                "tabIndex": 2
              },
              "validation": {
                "required": true
              }
            }
          ]
        }
      ]
    },
    {
      "id": "row-2",
      "columns": [
        {
          "id": "col-3",
          "width": 12,
          "fields": [
            {
              "id": "field-3",
              "type": "email",
              "props": {
                "key": "email",
                "label": "Email Address",
                "placeholder": "[email protected]",
                "tooltip": "We'll never share your email",
                "tabIndex": 3
              },
              "validation": {
                "required": true
              }
            }
          ]
        }
      ]
    },
    {
      "id": "row-3",
      "columns": [
        {
          "id": "col-4",
          "width": 12,
          "fields": [
            {
              "id": "field-4",
              "type": "dropdown",
              "props": {
                "key": "country",
                "label": "Country",
                "optionsString": "USA\nCanada\nUK\nGermany\nFrance\nOther",
                "tabIndex": 4
              }
            }
          ]
        }
      ]
    },
    {
      "id": "row-4",
      "columns": [
        {
          "id": "col-5",
          "width": 12,
          "fields": [
            {
              "id": "field-5",
              "type": "textarea",
              "props": {
                "key": "message",
                "label": "Message",
                "placeholder": "How can we help you?",
                "tabIndex": 5
              },
              "validation": {
                "required": true,
                "minLength": 10,
                "maxLength": 500
              }
            }
          ]
        }
      ]
    },
    {
      "id": "row-5",
      "columns": [
        {
          "id": "col-6",
          "width": 12,
          "fields": [
            {
              "id": "field-6",
              "type": "button",
              "props": {
                "key": "submit",
                "label": "Submit",
                "buttonConfig": {
                  "buttonType": "submit",
                  "variant": "primary",
                  "actionType": "submit"
                }
              }
            }
          ]
        }
      ]
    }
  ]
}

Integration with JetDesk

import { FormBuilder } from '@enerjisaformlibrary/formbuilder-react';
import '@enerjisaformlibrary/formbuilder-react/styles.css';

function FormEditor({ formId }) {
  const [initialSchema, setInitialSchema] = useState(null);

  useEffect(() => {
    // Load existing form from database
    fetch(`/api/forms/${formId}`)
      .then(res => res.json())
      .then(data => setInitialSchema(data.schema));
  }, [formId]);

  const handleSave = async (schema) => {
    await fetch(`/api/forms/${formId}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ schema })
    });
  };

  if (!initialSchema) return <div>Loading...</div>;

  return (
    <FormBuilder
      initialSchema={initialSchema}
      onSave={handleSave}
    />
  );
}

Keyboard Shortcuts

  • Ctrl/Cmd + Z: Undo
  • Ctrl/Cmd + Shift + Z: Redo

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

Changelog

1.0.22

  • Fixed: tabIndex now properly applied to all interactive field types (dropdown, checkbox, radio, toggle, slider, autocomplete, daterange)

1.0.21

  • Added: Comprehensive undo/redo functionality with 50-state history
  • Each form modification creates a separate history entry

License

MIT