@anarchitects/forms-ts
Schema-first form configuration and validation library built with TypeBox. Define forms declaratively and generate runtime validation schemas automatically.
Features
- 🏗️ Declarative Form Configuration - Define forms with field types, validation rules, and UI metadata
- ⚡ Runtime Schema Generation - Automatically generate TypeBox schemas from form configs
- 🔒 Type Safety - Full TypeScript support with inferred types
- 🎯 Field Validation - Built-in support for strings, emails, textareas, booleans, selects, and file uploads
- 🛡️ Security Features - Honeypot and CAPTCHA integration options
- 📧 Delivery Configuration - Email notifications and webhook support
Installation
npm install @anarchitects/forms-ts @sinclair/typebox
Usage
import { FormConfig, contactForm } from '@anarchitects/forms-ts';
import { schemaFromConfig } from '@anarchitects/forms-ts/builders';
import { Value } from '@sinclair/typebox/value';
// Use the predefined contact form configuration
console.log(contactForm);
// {
// id: 'contact_default',
// version: 1,
// fields: [
// { name: 'name', kind: 'string', required: true, minLength: 2, maxLength: 100, ui: { label: 'Name' } },
// { name: 'email', kind: 'email', required: true, ui: { label: 'Email' } },
// { name: 'message', kind: 'textarea', required: true, minLength: 10, maxLength: 3000, ui: { label: 'Message', rows: 6 } },
// { name: 'consent', kind: 'boolean', required: true, ui: { label: 'I agree' } }
// ],
// security: { honeypot: 'website', captcha: 'none' },
// delivery: { adminEmail: 'admin@site.tld', autoReply: { enabled: true, templateId: 'contact_autoreply' } }
// }
// Generate validation schema from form config
const schema = schemaFromConfig(contactForm);
// Validate form submission data
const formData = {
name: 'John Doe',
email: 'john@example.com',
message: 'Hello world! This is a test message.',
consent: true,
};
const isValid = Value.Check(schema, formData);
console.log(isValid); // true
// Get validation errors
const errors = [...Value.Errors(schema, formData)];
console.log(errors); // []
Field Types
String Field
{
name: 'username',
kind: 'string',
required: true,
minLength: 3,
maxLength: 20,
pattern: '^[a-zA-Z0-9_]+$',
ui: { label: 'Username', placeholder: 'Enter username' }
}
Email Field
{
name: 'email',
kind: 'email',
required: true,
ui: { label: 'Email Address' }
}
Textarea Field
{
name: 'description',
kind: 'textarea',
required: false,
maxLength: 500,
ui: { label: 'Description', rows: 4, help: 'Optional description' }
}
Boolean Field
{
name: 'subscribe',
kind: 'boolean',
required: true,
ui: { label: 'Subscribe to newsletter' }
}
Select Field
{
name: 'country',
kind: 'select',
required: true,
options: [
{ value: 'us', label: 'United States' },
{ value: 'uk', label: 'United Kingdom' },
{ value: 'ca', label: 'Canada' }
],
ui: { label: 'Country' }
}
File Upload Field
{
name: 'attachment',
kind: 'file',
required: false,
ui: { label: 'Upload File', help: 'Max 10MB' }
}
Using DTOs for API Integration
import { FormDefinitionRequestDTO, SubmissionRequestDTO } from '@anarchitects/forms-ts/dtos';
// Request a form definition
const formRequest: FormDefinitionRequestDTO = {
formId: 'contact_default',
formVersion: 1,
};
// Submit form data
const submission: SubmissionRequestDTO = {
formId: 'contact_default',
formVersion: 1,
payload: {
name: 'John Doe',
email: 'john@example.com',
message: 'Hello world!',
consent: true,
},
};
Security Configuration
const secureForm: FormConfig = {
// ... other config
security: {
honeypot: 'website', // Honeypot field name
captcha: 'turnstile', // 'turnstile' | 'hcaptcha' | 'none'
},
};
Delivery Configuration
const formWithDelivery: FormConfig = {
// ... other config
delivery: {
adminEmail: 'admin@example.com',
subject: 'New Contact Form Submission',
templateId: 'contact_template',
autoReply: {
enabled: true,
subject: 'Thank you for contacting us',
templateId: 'contact_autoreply',
},
webhooks: [
{
url: 'https://api.example.com/webhook',
secret: 'webhook-secret',
},
],
},
};
API Reference
Types
FormConfig- Main form configuration interfaceFormField- Individual field configurationFieldKind- Union of supported field types ('string' | 'email' | 'textarea' | 'boolean' | 'select' | 'file')FormDefinitionRequestDTO- Request DTO for fetching form definitionsFormDefinitionResponseDTO- Response DTO containing complete form configurationSubmissionRequestDTO- Request DTO for form submissionsSubmissionResponseDTO- Response DTO for submission results
Functions
schemaFromConfig(config: FormConfig)- Generate TypeBox schema from form configuration
Pre-defined Forms
contactForm- Ready-to-use contact form configuration with name, email, message, and consent fields
Exports
The library provides subpath exports for better tree-shaking:
// Main exports (models and predefined forms)
import { FormConfig, FormField, contactForm } from '@anarchitects/forms-ts';
// Models only
import { FormField, FieldKind, FormConfig } from '@anarchitects/forms-ts/models';
// DTOs only
import { FormDefinitionRequestDTO, FormDefinitionResponseDTO, SubmissionRequestDTO, SubmissionResponseDTO } from '@anarchitects/forms-ts/dtos';
// Builders only
import { schemaFromConfig } from '@anarchitects/forms-ts/builders';
Development notes
- Treat this package as the source of truth for form DTO/model contracts.
- Keep builder behavior deterministic and framework-agnostic.
- Regenerate API artifacts and verify contract tests when DTO schemas change.
Contributing
This library is part of the Anarchitecture Bricks monorepo. See the main repository for contribution guidelines.
License
Released under the Apache License 2.0.