Core Concepts
This page explains the fundamental concepts of the forms package.
FormComposer
The builder provides a fluent API for registering components and creating immutable engine instances.
import { FormComposer } from '@schema-engine/forms';
// Mock registrations for this example
const textInputRegistration = { $type: 'text', schema: {}, metadata: {}, render: () => null } as any;
const cardLayoutRegistration = { $type: 'card', schema: {}, metadata: {}, render: () => null } as any;
const wizardStepperRegistration = { $type: 'wizard', schema: {}, metadata: {}, render: () => null } as any;
const submitActionRegistration = { $type: 'submit', schema: {}, metadata: {}, execute: async () => ({}) } as any;
const engine = new FormComposer()
.addElement(textInputRegistration)
.addLayout(cardLayoutRegistration)
.addStepper(wizardStepperRegistration)
.addAction(submitActionRegistration)
.build();Features:
- Type-safe component registration with full TypeScript inference
- Method chaining for readable configuration
- Automatic validation of duplicate registrations
- Immutable engine instances after build
- Support for custom registry implementations via dependency injection
FormEngine
The immutable runtime engine created by the builder. Provides methods for:
- Retrieving registered components by ID
- Validating form configurations against registered schemas
- Generating JSON schemas for form builders and documentation
- Creating type-safe form instances
Component Registration
All components share a common registration pattern:
interface BaseRegistration<TConfig, TMeta> {
$type: string; // Unique identifier
schema: z.ZodType<TConfig>; // Zod schema for validation
metadata: TMeta; // Component metadata
}Elements
Elements are form fields and content components categorized by purpose:
- input - Form inputs (text, email, select, etc.)
- content - Static content (headings, paragraphs, images)
- decoration - Visual elements (dividers, spacers)
- interactive - Interactive components (buttons, links)
import type { ElementRegistration } from '@schema-engine/forms';
import { z } from 'zod';
const TextInputConfigSchema = z.object({
id: z.string(),
name: z.string(),
label: z.string(),
placeholder: z.string().optional(),
});
export const textInputRegistration: ElementRegistration<z.infer<typeof TextInputConfigSchema>> = {
$type: 'text',
schema: TextInputConfigSchema,
metadata: {
name: 'Text Input',
description: 'Single-line text input field',
category: 'input',
icon: 'text',
},
render: (props) => YourTextInputComponent(props),
};Layouts
Layouts wrap form content and provide structural organization:
import type { LayoutRegistration } from '@schema-engine/forms';
export const cardLayoutRegistration: LayoutRegistration<CardConfig> = {
$type: 'card',
schema: CardLayoutConfigSchema,
metadata: {
name: 'Card Layout',
description: 'Display form in a centered card container',
icon: 'card',
},
render: (props) => YourCardComponent(props),
};Steppers
Steppers control multi-step form navigation and state:
import type { StepperRegistration } from '@schema-engine/forms';
export const wizardStepperRegistration: StepperRegistration<WizardConfig> = {
$type: 'wizard',
schema: WizardStepperConfigSchema,
metadata: {
name: 'Wizard Stepper',
description: 'Step-by-step wizard navigation with progress indicator',
icon: 'wizard',
},
render: (props) => YourWizardComponent(props),
};Actions
Actions are event handlers that execute in response to form lifecycle events. See the Actions page for details.