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

@netpad/forms

v0.2.0

Published

Render NetPad forms in your React applications. Build sophisticated multi-page wizards with conditional logic, computed fields, and MongoDB integration.

Readme

@netpad/forms

Build sophisticated multi-page wizards and data collection forms in hours, not weeks.

npm version License: Apache-2.0

Why @netpad/forms?

Building forms is tedious. Multi-page wizards, conditional logic, validation, nested data structures — it all adds up to weeks of development time. @netpad/forms handles all of this with a simple, declarative configuration.

See it in action: Check out the Employee Onboarding Demo — a complete 3-page wizard in under 300 lines of code.

Features

  • 28+ Field Types — Text, email, date, select, rating, file upload, and more
  • Multi-page Wizards — Progress tracking, page navigation, step validation
  • Conditional Logic — Show/hide fields based on user input
  • Computed Fields — Formula-based calculated values
  • Nested Data — Dot notation paths create structured objects automatically
  • Validation — Required, min/max, pattern matching, custom rules
  • TypeScript — Full type safety with exported types
  • Theming — Customizable with Material-UI integration

Installation

npm install @netpad/forms

Peer Dependencies

npm install react react-dom @mui/material @mui/icons-material @emotion/react @emotion/styled

Quick Start

import { FormRenderer, FormConfiguration } from '@netpad/forms';

const contactForm: FormConfiguration = {
  name: 'Contact Form',
  fieldConfigs: [
    { path: 'name', label: 'Name', type: 'short_text', included: true, required: true },
    { path: 'email', label: 'Email', type: 'email', included: true, required: true },
    { path: 'message', label: 'Message', type: 'long_text', included: true, required: true },
  ],
  submitButtonText: 'Send Message',
};

function ContactPage() {
  const handleSubmit = async (data: Record<string, unknown>) => {
    await fetch('/api/contact', { method: 'POST', body: JSON.stringify(data) });
  };

  return <FormRenderer config={contactForm} onSubmit={handleSubmit} />;
}

Multi-Page Wizards

Create step-by-step forms with progress tracking:

const formConfig: FormConfiguration = {
  name: 'Employee Onboarding',
  fieldConfigs: [
    { path: 'firstName', label: 'First Name', type: 'short_text', included: true, required: true },
    { path: 'lastName', label: 'Last Name', type: 'short_text', included: true, required: true },
    { path: 'email', label: 'Email', type: 'email', included: true, required: true },
    { path: 'department', label: 'Department', type: 'dropdown', included: true, options: [
      { label: 'Engineering', value: 'engineering' },
      { label: 'Marketing', value: 'marketing' },
    ]},
    { path: 'startDate', label: 'Start Date', type: 'date', included: true, required: true },
  ],
  multiPage: {
    enabled: true,
    showProgressBar: true,
    pages: [
      { id: 'personal', title: 'Personal Info', fields: ['firstName', 'lastName', 'email'] },
      { id: 'employment', title: 'Employment', fields: ['department', 'startDate'] },
    ],
  },
};

Conditional Logic

Show or hide fields based on other field values:

{
  path: 'officeLocation',
  label: 'Office Location',
  type: 'dropdown',
  included: true,
  options: [...],
  conditionalLogic: {
    action: 'show',
    logicType: 'any',
    conditions: [
      { field: 'workLocation', operator: 'equals', value: 'hybrid' },
      { field: 'workLocation', operator: 'equals', value: 'onsite' },
    ],
  },
}

Available operators: equals, notEquals, contains, notContains, greaterThan, lessThan, isEmpty, isNotEmpty, isTrue, isFalse

Nested Data Structures

Use dot notation for nested objects:

{ path: 'emergencyContact.name', label: 'Contact Name', type: 'short_text', included: true }
{ path: 'emergencyContact.phone', label: 'Contact Phone', type: 'phone', included: true }

Produces:

{
  "emergencyContact": {
    "name": "Jane Doe",
    "phone": "555-1234"
  }
}

Computed Fields

Calculate values based on other fields:

{
  path: 'total',
  label: 'Order Total',
  type: 'number',
  included: true,
  disabled: true,
  computed: {
    formula: 'quantity * unitPrice * (1 - discount)',
    dependencies: ['quantity', 'unitPrice', 'discount'],
  },
}

API Reference

FormRenderer Props

| Prop | Type | Description | |------|------|-------------| | config | FormConfiguration | Form configuration with fields, pages, and settings | | initialData | Record<string, unknown> | Initial form data (for edit mode) | | mode | 'create' \| 'edit' \| 'view' | Form mode (default: 'create') | | onSubmit | (data) => Promise<void> | Called on form submission | | onChange | (data) => void | Called when form data changes | | onError | (errors) => void | Called on validation errors | | submitButtonText | string | Custom submit button text | | showSubmitButton | boolean | Show/hide submit button (default: true) | | disabled | boolean | Disable all form inputs | | loading | boolean | Show loading state | | theme | FormTheme | Theme overrides |

Supported Field Types

| Type | Description | |------|-------------| | short_text | Single-line text input | | long_text | Multi-line text area | | email | Email with validation | | url | URL with validation | | phone | Phone number | | number | Numeric input | | dropdown | Select dropdown | | multiple_choice | Radio buttons | | checkboxes | Checkbox group | | yes_no | Boolean switch | | date | Date picker | | time | Time picker | | rating | Star rating | | slider | Numeric slider | | tags | Tag/chip input | | autocomplete | Searchable select |

NetPad API Client

Connect to a NetPad instance:

import { createNetPadClient } from '@netpad/forms';

const client = createNetPadClient({
  baseUrl: 'https://your-netpad-instance.com',
  apiKey: 'np_live_xxx',
});

// Fetch form configuration
const form = await client.getForm('employee-onboarding');

// Submit form data
await client.submitForm('employee-onboarding', formData);

// List submissions
const submissions = await client.listSubmissions('employee-onboarding', { page: 1 });

Utility Functions

import {
  evaluateConditionalLogic,
  validateField,
  validateForm,
  evaluateFormula,
} from '@netpad/forms';

// Check if field should be visible
const isVisible = evaluateConditionalLogic(field.conditionalLogic, formData);

// Validate a single field
const error = validateField(field, value);

// Validate entire form
const errors = validateForm(fields, formData);

// Evaluate a formula
const result = evaluateFormula('quantity * price', { quantity: 5, price: 10 });

Theming

Customize the form appearance:

const theme: FormTheme = {
  primaryColor: '#00ED64',
  backgroundColor: '#ffffff',
  textColor: '#001E2B',
  borderRadius: 8,
  spacing: 'comfortable',
  inputStyle: 'outlined',
  mode: 'light',
};

<FormRenderer config={formConfig} theme={theme} onSubmit={handleSubmit} />

TypeScript

All types are exported:

import type {
  FormConfiguration,
  FieldConfig,
  FormTheme,
  ConditionalLogic,
  FormPage,
  MultiPageConfig,
} from '@netpad/forms';

Examples

License

Apache-2.0


Questions? Open an issue or check the documentation.