Quick Start

Build your first form with Schema Engine in just a few steps.

1. Create Your Form Engine

Use the createReactFormComposer to register components and build an immutable engine:

// lib/form-engine.ts
import { createReactFormComposer } from '@schema-engine/forms-react';
import {
	InputElementRegistration,
	TextareaElementRegistration,
	SelectElementRegistration,
	CardLayoutRegistration,
	DefaultStepperRegistration,
} from '@schema-engine/forms-react/registrations';
 
export const formEngine = createReactFormComposer()
	.addElement(InputElementRegistration)
	.addElement(TextareaElementRegistration)
	.addElement(SelectElementRegistration)
	.addLayout(CardLayoutRegistration)
	.addStepper(DefaultStepperRegistration)
	.build();

Note: Create the form engine once and reuse it across your entire application. The engine instance is immutable after calling build().

2. Create the Form Configuration

Define your form structure using a JSON configuration:

import type { FormConfig } from '@schema-engine/forms';
 
// config/contact-form.ts
const contactFormConfig: FormConfig = {
	id: 'contact-form',
	title: 'Get In Touch',
	description: 'We would love to hear from you',
	steps: [
		{
			id: 'contact-details',
			title: 'Contact Information',
			elements: [
				{
					$type: 'input',
					id: 'firstName',
					name: 'firstName',
					label: 'First Name',
					inputType: 'text',
					rules: [{ rule: 'required', message: 'First name is required' }],
				},
				{
					$type: 'input',
					id: 'email',
					name: 'email',
					label: 'Email Address',
					inputType: 'email',
					rules: [
						{ rule: 'required', message: 'Email is required' },
						{ rule: 'email', message: 'Please enter a valid email address' },
					],
				},
				{
					$type: 'select',
					id: 'subject',
					name: 'subject',
					label: 'Subject',
					options: [
						{ value: 'general', label: 'General Inquiry' },
						{ value: 'support', label: 'Technical Support' },
						{ value: 'billing', label: 'Billing Question' },
					],
					rules: [{ rule: 'required', message: 'Please select a subject' }],
				},
				{
					$type: 'select',
					id: 'priority',
					name: 'priority',
					label: 'Priority Level',
					options: [
						{ value: 'low', label: 'Low' },
						{ value: 'medium', label: 'Medium' },
						{ value: 'high', label: 'High' },
					],
					constraints: [
						{
							field: 'subject',
							operator: 'equals',
							value: 'support',
							action: 'show',
						},
					],
				},
				{
					$type: 'textarea',
					id: 'message',
					name: 'message',
					label: 'Message',
					rows: 4,
					rules: [
						{ rule: 'required', message: 'Message is required' },
						{ rule: 'minLength', value: 10, message: 'Message must be at least 10 characters' },
					],
				},
			],
			layout: {
				$type: 'card',
				padding: 'md',
				shadowSize: 'md',
			},
		},
	],
};

3. Render the Form

import { FormEngineProvider, FormRenderer } from '@schema-engine/forms-react';
import { formEngine } from './lib/form-engine'; // Adjust path as needed
import { contactFormConfig } from './config/contact-form'; // Import the config created above
 
export function ContactForm() {
	const handleSubmit = (data: any) => {
		console.log('Form submitted:', data);
	};
 
	return (
		<FormEngineProvider engine={formEngine}>
			<FormRenderer
				config={contactFormConfig}
				onSubmit={handleSubmit}
			/>
		</FormEngineProvider>
	);
}

Understanding Constraint Logic

Notice the priority field includes a constraints array:

{
	"$type": "select",
	"id": "priority",
	"name": "priority",
	"label": "Priority Level",
	"constraints": [
		{
			"field": "subject",
			"operator": "equals",
			"value": "support",
			"action": "show"
		}
	]
}

This creates conditional logic where:

  • The priority field is only shown when the subject field equals "support"
  • The field automatically hides/shows as users change the subject

Available operators: equals, not_equals, contains, not_contains, greater_than, less_than, is_empty, is_not_empty

Available actions: show, hide, enable, disable, require

Key Concepts

Form Config Structure

interface FormConfig {
	id: string;           // Unique identifier
	title?: string;       // Form title
	description?: string; // Form description
	steps: StepConfig[];  // Form steps (even single-step forms need this)
	stepper?: StepperConfig; // Optional stepper configuration
	actions?: ActionConfig[]; // Optional form actions
}

Element Configuration

interface ElementConfig {
	$type: string;        // Element type (input, select, textarea, etc.)
	id?: string;          // DOM element ID
	name: string;         // Form field name
	label?: string;       // Field label
	rules?: ValidationRule[]; // Validation rules
	constraints?: ConstraintLogic[]; // Conditional logic
	grid?: ElementGridConfig; // Grid positioning
	// ... type-specific properties
}

Validation Rules

Schema Engine uses a declarative validation system:

// Required field
rules: [{ rule: 'required', message: 'This field is required' }]
 
// Email validation
rules: [
	{ rule: 'required', message: 'Email is required' },
	{ rule: 'email', message: 'Please enter a valid email' },
]
 
// Length validation
rules: [
	{ rule: 'minLength', value: 3, message: 'Must be at least 3 characters' },
	{ rule: 'maxLength', value: 100, message: 'Must be less than 100 characters' },
]
 
// Pattern validation
rules: [
	{
		rule: 'pattern',
		value: '^[A-Za-z\\s]+$',
		message: 'Only letters and spaces allowed',
	},
]

What's Next?

Now that you've built your first form, explore these topics:

  • Components - Pre-built elements and custom components
  • Layouts - Visual structure for forms
  • Steppers - Multi-step form navigation
  • Hooks - React hooks for form interactions
  • Actions - Handle form submission and lifecycle events