Faster Development
Less Code
Type Safe
// form-components/TextField.tsx (1 of 15+ components)
import { useState, useEffect } from 'react';
interface TextFieldProps {
label: string;
value: string;
onChange: (value: string) => void;
error?: string;
required?: boolean;
placeholder?: string;
disabled?: boolean;
minLength?: number;
maxLength?: number;
pattern?: RegExp;
helpText?: string;
}
export function TextField({
label, value, onChange, error, required,
placeholder, disabled, minLength, maxLength,
pattern, helpText
}: TextFieldProps) {
const [touched, setTouched] = useState(false);
const [localError, setLocalError] = useState<string>();
useEffect(() => {
if (!touched) return;
if (required && !value) {
setLocalError(`${label} is required`);
} else if (minLength && value.length < minLength) {
setLocalError(`Min ${minLength} characters`);
} else if (maxLength && value.length > maxLength) {
setLocalError(`Max ${maxLength} characters`);
} else if (pattern && !pattern.test(value)) {
setLocalError('Invalid format');
} else {
setLocalError(undefined);
}
}, [value, touched, required, minLength, maxLength]);
return (
<div className="form-field">
<label>{label}{required && '*'}</label>
<input
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
onBlur={() => setTouched(true)}
placeholder={placeholder}
disabled={disabled}
/>
{helpText && <span className="help">{helpText}</span>}
{(error || localError) && (
<span className="error">{error || localError}</span>
)}
</div>
);
}
// Repeat for: EmailField, PhoneField, SelectField,
// DateField, CheckboxField, RadioField, TextArea,
// NumberField, SliderField, RatingField, FileUpload,
// AutocompleteField, TagsField, SwitchField...
// form-logic/useMultiPageForm.ts
export function useMultiPageForm(config) {
const [currentPage, setCurrentPage] = useState(0);
const [formData, setFormData] = useState({});
const [errors, setErrors] = useState({});
const [visited, setVisited] = useState(new Set());
const validatePage = (pageIndex: number) => {
const pageFields = config.pages[pageIndex].fields;
const pageErrors = {};
// ... 50+ lines of validation logic
};
const nextPage = () => {
if (validatePage(currentPage)) {
setCurrentPage(prev => prev + 1);
}
};
// ... 100+ more lines for prev, submit, etc.
}
// form-logic/conditionalLogic.ts
export function evaluateConditions(conditions, data) {
// ... 80+ lines of condition evaluation
}
// form-logic/nestedData.ts
export function setNestedValue(obj, path, value) {
// ... 40+ lines of nested object handling
}
// Plus: API routes, database schemas, error handling,
// accessibility, testing, documentation...
// Total: 2000+ lines across 20+ files
// Time: 2-4 weeks of development// app/onboarding/page.tsx - THE ENTIRE FORM
import { FormRenderer, FormConfiguration } from '@netpad/forms';
const onboardingForm: FormConfiguration = {
name: 'Employee Onboarding',
fieldConfigs: [
{
path: 'firstName',
label: 'First Name',
type: 'short_text',
included: true,
required: true,
fieldWidth: 'half',
},
{
path: 'email',
label: 'Email',
type: 'email',
included: true,
required: true,
},
{
path: 'department',
label: 'Department',
type: 'dropdown',
included: true,
options: [
{ label: 'Engineering', value: 'eng' },
{ label: 'Marketing', value: 'mkt' },
],
},
{
path: 'officeLocation',
label: 'Office',
type: 'dropdown',
included: true,
conditionalLogic: {
action: 'show',
conditions: [
{ field: 'workType', operator: 'equals', value: 'hybrid' }
],
},
},
{
path: 'emergencyContact.name',
label: 'Emergency Contact',
type: 'short_text',
included: true,
},
{
path: 'emergencyContact.phone',
label: 'Contact Phone',
type: 'phone',
included: true,
},
],
multiPage: {
enabled: true,
showProgressBar: true,
pages: [
{ id: 'personal', title: 'Personal', fields: ['firstName', 'email'] },
{ id: 'work', title: 'Employment', fields: ['department', 'officeLocation'] },
{ id: 'emergency', title: 'Emergency', fields: ['emergencyContact.name', 'emergencyContact.phone'] },
],
},
};
export default function OnboardingPage() {
const handleSubmit = async (data) => {
await fetch('/api/onboarding', {
method: 'POST',
body: JSON.stringify(data),
});
};
return <FormRenderer config={onboardingForm} onSubmit={handleSubmit} />;
}
// That's it. ~80 lines. Ships today.| Feature | Build From Scratch | With NetPad |
|---|---|---|
| Text, Email, Phone fields | 3 components (~150 lines) | Built-in |
| Date/Time pickers | 2 components + library | Built-in |
| Dropdowns, Radio, Checkbox | 3 components (~200 lines) | Built-in |
| File upload | 1 component + S3 setup | Built-in |
| Multi-page wizard | Custom state machine (~300 lines) | 5 lines of config |
| Progress indicator | Custom component (~100 lines) | 1 boolean flag |
| Field validation | Per-field + form-level (~200 lines) | Declarative config |
| Conditional logic | Custom evaluator (~150 lines) | JSON conditions |
| Nested data (contact.phone) | Utility functions (~80 lines) | Dot notation |
| Computed fields | Custom formula parser | Formula strings |
| Error display | Custom error handling | Automatic |
| Accessibility (ARIA) | Manual implementation | Built-in |
Build 15+ field components
Implement validation logic
Handle conditional visibility
Manage multi-page state
Style everything from scratch
28+ field types included
Declarative validation
JSON-based conditions
Config-driven wizards
Themeable out of the box
Design state machine
Build approval chains
Implement notifications
Handle edge cases
Add audit logging
Visual workflow builder
Pre-built approval patterns
Email/Slack integration
Automatic retries
Built-in audit trail
Design database schema
Build CRUD APIs
Implement search/filter
Add pagination
Build admin dashboard
Automatic MongoDB storage
REST API included
Full-text search
Built-in pagination
Admin dashboard ready
Forms + Workflows + Data Management
5,000+ lines of code
Ongoing maintenance burden
All three capabilities integrated
~100 lines of configuration
Maintained by NetPad team
Free MongoDB Atlas cluster included. No credit card required.
Install the npm package and render NetPad forms directly in your React applications. Perfect for custom integrations and embedded forms.
$ npm install @netpad/forms
Trigger and manage workflow executions programmatically from your backend services, cron jobs, or CI/CD pipelines.
$ npm install @netpad/workflows
Clone a complete working example with a 3-page wizard, conditional fields, nested data structures, and validation — all in under 300 lines of code.
$ git clone examples/employee-onboarding-demo
NetPad — The Complete MongoDB Data Platform