@formdown/core (Phase 2 Complete)
The core package provides the Core-First Architecture foundation with FormManager and 4 Core modules for complete form lifecycle management.
FormManager Class
The FormManager is the central API for all form operations in Formdown. It provides complete form lifecycle management with reactive data binding, Core module coordination, and event-driven architecture.
Phase 2 Achievement: 12+ new methods for UI/Editor integration, 100% Core module utilization.
Constructor
new FormManager(options?: FormManagerOptions)
interface FormManagerOptions {
preserveMarkdown?: boolean
fieldPrefix?: string
inlineFieldDelimiter?: string
autoGenerateFormIds?: boolean
theme?: Record<string, any>
}
Core Methods
parse(content: string): FormdownContent
Parses Formdown content and initializes the form manager with schema and data binding.
Parameters:
content
(string): The Formdown source code
Returns: FormdownContent
- Parsed form structure
Example:
import { FormManager } from '@formdown/core';
const manager = new FormManager();
const result = manager.parse('@name*: [placeholder="Enter name"]');
// Returns parsed content and initializes internal schema
Core Module APIs (Phase 2 New)
createFieldProcessor(): FieldProcessor
Creates a FieldProcessor instance for advanced field processing.
Returns: FieldProcessor
- Field processing module
Example:
const processor = manager.createFieldProcessor();
const fieldType = processor.getFieldType(element);
const value = processor.extractFieldValue(element, fieldType);
createDOMBinder(): DOMBinder
Creates a DOMBinder instance for DOM manipulation and binding.
Returns: DOMBinder
- DOM binding module
Example:
const binder = manager.createDOMBinder();
binder.setupElementEventHandlers(container, handler);
binder.syncFormData(formData, container);
createValidationManager(): ValidationManager
Creates a ValidationManager for advanced validation pipelines.
Returns: ValidationManager
- Validation management module
Example:
const validator = manager.createValidationManager();
const result = await validator.validateAsync(fieldContext, value, formData);
createEventOrchestrator(): EventOrchestrator
Creates an EventOrchestrator for component coordination.
Returns: EventOrchestrator
- Event orchestration module
Example:
const orchestrator = manager.createEventOrchestrator();
const bridgeId = orchestrator.createCoreUIBridge(coreComponent, uiComponent);
UI/Editor Integration APIs (Phase 2 New)
renderToTemplate(options?: any): any
Render form to template format for UI components.
Returns: Structured template data for component rendering
createPreviewTemplate(content: string): any
Create preview template for editor components.
Parameters:
content
(string): Formdown content for preview
Returns: Preview template with HTML, errors, and schema
handleUIEvent(event: Event, domBinder?: DOMBinder): void
Handle UI events from components through Core modules.
Parameters:
event
(Event): DOM event from UI componentdomBinder
(DOMBinder, optional): DOMBinder instance
setupComponentBridge(target: any): string
Setup component bridge using EventOrchestrator.
Parameters:
target
(any): Target component for bridge
Returns: Bridge ID for coordination
render(options?: RenderOptions): string
Renders the parsed form to HTML with current data values.
Parameters:
options
(RenderOptions, optional): Rendering options
interface RenderOptions {
theme?: Record<string, any>
customAttributes?: Record<string, any>
outputFormat?: 'html' | 'json'
}
Returns: HTML string or JSON based on output format
Example:
const manager = new FormManager();
manager.parse('@email*: @[]');
manager.setFieldValue('email', 'user@example.com');
const html = manager.render();
// Returns HTML with email field pre-filled
getData(): Record<string, any>
Gets current form data with proper value priority (context.data
> schema value
> empty
).
Returns: Current form data object
Example:
const data = manager.getData();
console.log(data); // { name: "John", email: "john@example.com" }
setFieldValue(field: string, value: any): void
Sets a single field value and triggers data change events.
Parameters:
field
(string): Field namevalue
(any): Value to set
Example:
manager.setFieldValue('priority', 'High');
// Triggers 'data-change' event automatically
updateData(newData: Record<string, any>): void
Updates multiple form fields at once.
Parameters:
newData
(Record<string, any>): Object with field values to update
Example:
manager.updateData({
name: 'Jane Smith',
email: 'jane@example.com',
age: 30
});
validate(): ValidationResult
Validates current form data against the schema.
Returns: ValidationResult
interface ValidationResult {
isValid: boolean
errors: FieldError[]
}
interface FieldError {
field: string
message: string
}
Example:
const result = manager.validate();
if (!result.isValid) {
console.log('Validation errors:', result.errors);
}
getSchema(): FormDownSchema | null
Gets the extracted form schema.
Returns: Schema object or null if no form is parsed
reset(): void
Resets form data to schema defaults and emits reset event.
isDirty(): boolean
Checks if form has unsaved changes from defaults.
Returns: true
if form data has changed from defaults
Event System
FormManager provides an event-driven architecture for reactive form interactions.
on<K extends keyof FormManagerEvents>(event: K, handler: Function): void
Subscribes to form events.
Events:
data-change
: Fired when field values changevalidation-error
: Fired when validation failsform-submit
: Fired on form submissionform-reset
: Fired when form is reset
Example:
manager.on('data-change', ({ field, value, formData }) => {
console.log(`Field ${field} changed to:`, value);
console.log('Current form data:', formData);
});
manager.on('validation-error', ({ field, errors }) => {
console.log(`Validation failed for ${field}:`, errors);
});
off<K extends keyof FormManagerEvents>(event: K, handler: Function): void
Unsubscribes from form events.
Utility Methods
getField(fieldName: string): Field | null
Gets field definition by name.
getFields(): Field[]
Gets all form fields.
getDefaultValues(): Record<string, any>
Gets default values from schema.
clone(): FormManager
Creates a new FormManager instance with same options.
export(): FormManagerExport
Exports form configuration for serialization.
import(config: FormManagerImport): void
Imports form configuration.
FormDataBinding Class
FormDataBinding provides reactive data management with schema-driven defaults and validation.
Constructor
new FormDataBinding(schema?: FormDownSchema, initialData?: Record<string, any>)
Core Methods
set(field: string, value: any): void
Sets a field value with change detection.
get(field: string): any
Gets a field value with priority: current data
> schema default
> undefined
.
getAll(): Record<string, any>
Gets all form data merging schema defaults with current values.
updateAll(newData: Record<string, any>): void
Updates multiple fields atomically.
reset(): void
Resets to schema defaults.
validate(): ValidationResult
Validates all fields against schema.
isDirty(): boolean
Checks if data differs from schema defaults.
subscribe(listener: ChangeListener): () => void
Subscribes to data changes. Returns unsubscribe function.
subscribeToField(listener: FieldChangeListener): () => void
Subscribes to specific field changes.
Convenience Functions
createFormManager(content: string, options?: FormManagerOptions): FormManager
Creates and initializes a FormManager in one call.
Example:
import { createFormManager } from '@formdown/core';
const manager = createFormManager(`
@name*: [placeholder="Enter name"]
@email*: @[]
`);
console.log(manager.getData()); // { name: "", email: "" }
renderForm(content: string, data?: Record<string, any>, options?: FormManagerOptions & RenderOptions): string
One-time form rendering convenience function.
Example:
import { renderForm } from '@formdown/core';
const html = renderForm(
'@name*: [placeholder="Enter name"]',
{ name: 'John Doe' }
);
// Returns HTML with name field pre-filled
Core Functions
parseFormdown(input: string): FormdownContent
Parses Formdown syntax into structured data containing both form fields and markdown content.
Parameters:
input
(string): The Formdown source code
Returns: FormdownContent
interface FormdownContent {
markdown: string; // Processed markdown with field placeholders
forms: Field[]; // Parsed form fields
}
Example:
import { parseFormdown } from '@formdown/core';
const result = parseFormdown('@name: [text required]\n\n# Contact Form');
// Returns: { markdown: "<!--FORMDOWN_FIELD_0-->\n\n# Contact Form", forms: [...] }
generateFormHTML(content: FormdownContent): string
Generates complete HTML including forms and markdown content.
Parameters:
content
(FormdownContent): Parsed formdown content
Returns: HTML string
Example:
import { parseFormdown, generateFormHTML } from '@formdown/core';
const parsed = parseFormdown('@name: [text required]');
const html = generateFormHTML(parsed);
// Returns: Complete HTML with form and markdown
getSchema(content: string): FormDownSchema
Extracts structured schema metadata from Formdown content.
Parameters:
content
(string): The Formdown source code
Returns: FormDownSchema
interface FormDownSchema {
[fieldName: string]: FieldSchema;
}
interface FieldSchema {
type: FieldType;
label?: string;
required?: boolean;
defaultValue?: any;
position?: number;
validation?: ValidationRules;
htmlAttributes?: Record<string, any>;
layout?: 'inline' | 'vertical';
}
Example:
import { getSchema } from '@formdown/core';
const schema = getSchema('@name: [text required minlength=2]');
// Returns: { name: { type: 'text', required: true, validation: { minlength: 2 } } }
FormdownFieldHelper
FormdownFieldHelper provides a predictable and rational API for interacting with Formdown form fields. It automatically handles "other" options across all field types and provides a consistent interface for getting and setting field values.
Core Methods
get(fieldName: string, form?: HTMLFormElement): FieldValue
Gets the current value(s) of a field.
Parameters:
fieldName
(string): Name of the fieldform
(HTMLFormElement, optional): Form element to search in
Returns:
- String for single-value fields (radio, select, text)
- String array for checkbox fields
null
if field not found
Example:
import { FormdownFieldHelper } from '@formdown/core';
// Radio/Select: single value
FormdownFieldHelper.get('priority') // → "Medium" | null
// Checkbox: array of values
FormdownFieldHelper.get('skills') // → ["JavaScript", "Rust"] | []
// Text: string value
FormdownFieldHelper.get('name') // → "John Doe" | null
set(fieldName: string, value: string | string[], options?: FieldHelperOptions): boolean
Sets field value(s). Automatically uses "other" option for values not in predefined options.
Parameters:
fieldName
(string): Name of the fieldvalue
(string | string[]): Value to setoptions
(FieldHelperOptions, optional): Configuration options
Returns: boolean
- Success status
Example:
// Set existing option
FormdownFieldHelper.set('priority', 'High') // → true
// Set other option (automatically detected)
FormdownFieldHelper.set('priority', 'Urgent') // → true (uses other option)
// Set checkbox values
FormdownFieldHelper.set('skills', ['JavaScript', 'CustomSkill']) // → true
// Set text field
FormdownFieldHelper.set('name', 'John Doe') // → true
clear(fieldName: string, options?: FieldHelperOptions): boolean
Clears all values from a field.
Parameters:
fieldName
(string): Name of the fieldoptions
(FieldHelperOptions, optional): Configuration options
Returns: boolean
- Success status
Example:
FormdownFieldHelper.clear('priority') // → true
FormdownFieldHelper.clear('skills') // → true (clears all checkboxes)
has(fieldName: string, value: string, form?: HTMLFormElement): boolean
Checks if a field has a specific value.
Parameters:
fieldName
(string): Name of the fieldvalue
(string): Value to check forform
(HTMLFormElement, optional): Form element to search in
Returns: boolean
- Whether the field has the value
Example:
FormdownFieldHelper.has('priority', 'High') // → true/false
FormdownFieldHelper.has('skills', 'JavaScript') // → true/false (searches in array)
Checkbox-Specific Methods
add(fieldName: string, value: string, options?: FieldHelperOptions): boolean
Adds a value to a checkbox field while preserving existing selections.
Parameters:
fieldName
(string): Name of the checkbox fieldvalue
(string): Value to addoptions
(FieldHelperOptions, optional): Configuration options
Returns: boolean
- Success status
Example:
FormdownFieldHelper.add('skills', 'Python') // Add to existing selections
FormdownFieldHelper.add('skills', 'CustomSkill') // Add as other option
remove(fieldName: string, value: string, options?: FieldHelperOptions): boolean
Removes a specific value from a checkbox field.
Parameters:
fieldName
(string): Name of the checkbox fieldvalue
(string): Value to removeoptions
(FieldHelperOptions, optional): Configuration options
Returns: boolean
- Success status
Example:
FormdownFieldHelper.remove('skills', 'JavaScript') // Remove specific value
toggle(fieldName: string, value: string, options?: FieldHelperOptions): boolean
Toggles a value in a checkbox field (add if not present, remove if present).
Parameters:
fieldName
(string): Name of the checkbox fieldvalue
(string): Value to toggleoptions
(FieldHelperOptions, optional): Configuration options
Returns: boolean
- Success status
Example:
FormdownFieldHelper.toggle('skills', 'Python') // Add or remove based on current state
Utility Methods
getFieldType(fieldName: string, form?: HTMLFormElement): FormFieldType
Gets the type of a field.
Parameters:
fieldName
(string): Name of the fieldform
(HTMLFormElement, optional): Form element to search in
Returns: FormFieldType
- Field type ('radio' | 'checkbox' | 'select' | 'text' | 'textarea' | 'unknown')
Example:
FormdownFieldHelper.getFieldType('priority') // → 'radio'
FormdownFieldHelper.getFieldType('skills') // → 'checkbox'
isOtherValue(fieldName: string, value: string, form?: HTMLFormElement): boolean
Checks if a value would be treated as an "other" option.
Parameters:
fieldName
(string): Name of the fieldvalue
(string): Value to checkform
(HTMLFormElement, optional): Form element to search in
Returns: boolean
- Whether the value would use the "other" option
Example:
FormdownFieldHelper.isOtherValue('priority', 'High') // → false (existing option)
FormdownFieldHelper.isOtherValue('priority', 'Urgent') // → true (other option)
Options Configuration
FieldHelperOptions
interface FieldHelperOptions {
silent?: boolean; // Suppress console warnings (default: false)
dispatchEvents?: boolean; // Dispatch change/input events (default: true)
}
Example:
FormdownFieldHelper.set('priority', 'Urgent', {
silent: true, // No warning messages
dispatchEvents: false // Don't trigger events
});
@formdown/ui (Phase 2.1 Complete)
The UI package provides web components for rendering Formdown content as interactive forms with 100% Core module integration.
Phase 2.1 Achievement: 1307 lines → 1186 lines (9.3% optimization), complete FormManager delegation, DOMBinder integration.
<formdown-ui>
Web Component
A custom element that renders Formdown source as interactive forms with Core-powered validation and data management.
Attributes
content
(string): The Formdown source contentform-id
(string): ID for the generated formshow-submit-button
(boolean): Show/hide submit buttonsubmit-text
(string): Text for submit buttonselect-on-focus
(boolean): Select text on focus
Properties
data
(Record<string, any>): Reactive data property that syncs with internal FormManager
Methods
validate(): ValidationResult
Validates all form fields and returns validation results with visual feedback.
Returns: ValidationResult
interface ValidationResult {
isValid: boolean;
errors: FieldError[];
}
Example:
const formdownUI = document.querySelector('formdown-ui');
const validation = formdownUI.validate();
if (!validation.isValid) {
console.log('Validation errors:', validation.errors);
// Fields with errors will be visually highlighted
}
getFormData(): Record<string, any>
Gets current form data.
Returns: Current form data object
Example:
const formdownUI = document.querySelector('formdown-ui');
const data = formdownUI.getFormData();
console.log('Form data:', data);
updateData(newData: Record<string, any>): void
Updates form data.
Parameters:
newData
(Record<string, any>): Data to update
Example:
const formdownUI = document.querySelector('formdown-ui');
formdownUI.updateData({ name: 'John Doe', email: 'john@example.com' });
updateField(fieldName: string, value: any): void
Updates a single field.
Parameters:
fieldName
(string): Field namevalue
(any): Field value
reset(): void
Resets the form to schema defaults.
Example:
const formdownUI = document.querySelector('formdown-ui');
formdownUI.reset();
isDirty(): boolean
Checks if form has unsaved changes.
Returns: true
if form data has changed from defaults
getSchema(): FormDownSchema | null
Gets the form schema.
Returns: Schema object or null
Events
formdown-change
: Fired when field values changeformdown-data-update
: Fired when form data updatesvalidation-error
: Fired when validation failsform-submit
: Fired on form submission
Example:
<formdown-ui content="@name: [text required]
@email: [email required]
@age: [number min=18]">
</formdown-ui>
<script>
const form = document.querySelector('formdown-ui');
// Listen for changes
form.addEventListener('formdown-change', (event) => {
console.log('Field changed:', event.detail);
});
// Validate form
document.getElementById('validate-btn').addEventListener('click', () => {
const result = form.validate();
if (result.isValid) {
console.log('Form is valid!', form.getFormData());
}
});
</script>
Utility Functions
createFormdownUI(container: HTMLElement, options?: UIOptions): FormdownUI
Creates and appends a FormdownUI component to a container.
Parameters:
container
(HTMLElement): Container to append tooptions
(UIOptions, optional): Configuration options
interface UIOptions {
content?: string
formId?: string
showSubmitButton?: boolean
submitText?: string
}
Example:
import { createFormdownUI } from '@formdown/ui';
const form = createFormdownUI(document.getElementById('form-container'), {
content: '@name: [text required]',
showSubmitButton: true,
submitText: 'Submit Form'
});
@formdown/editor (Phase 2.2 Complete)
The editor package provides a live editor component with 100% Core module integration and real-time Core-powered preview capabilities.
Phase 2.2 Achievement: Complete EventOrchestrator integration, legacy code elimination, template consolidation (505 lines + templates.ts removal).
<formdown-editor>
Web Component
A live editor with Core-powered real-time preview, FormManager data management, and EventOrchestrator coordination.
Attributes
content
(string): Initial Formdown contentmode
("edit" | "split" | "view"): Display mode (default: "split")placeholder
(string): Placeholder text for editorheader
(boolean): Show header bartoolbar
(boolean): Show toolbar
Properties
data
(Record<string, any>): Form data that syncs with preview
Methods
validate(): ValidationResult
Validates the form in the preview panel.
Returns: ValidationResult
Example:
const editor = document.querySelector('formdown-editor');
const validation = editor.validate();
if (!validation.isValid) {
console.log('Form validation failed:', validation.errors);
// Preview panel will show visual validation feedback
}
getFormData(): Record<string, any>
Gets current form data from the preview panel.
Returns: Current form data object
Example:
const editor = document.querySelector('formdown-editor');
const data = editor.getFormData();
console.log('Current form data:', data);
Events
formdown-change
: Fired when content changesformdown-data-update
: Fired when preview form data changes
Example:
<formdown-editor mode="split">
@name: [text required placeholder="Enter your name"]
@email: [email required]
@age: [number min=18 max=120]
</formdown-editor>
<script>
const editor = document.querySelector('formdown-editor');
// Validate the form in preview
document.getElementById('validate-btn').addEventListener('click', () => {
const result = editor.validate();
console.log('Validation result:', result);
});
// Get form data
document.getElementById('get-data-btn').addEventListener('click', () => {
const data = editor.getFormData();
console.log('Form data:', data);
});
</script>
Utility Functions
createFormdownEditor(container: HTMLElement, options?: EditorOptions): FormdownEditor
Creates and appends a FormdownEditor component to a container.
Parameters:
container
(HTMLElement): Container to append tooptions
(EditorOptions, optional): Configuration options
interface EditorOptions {
content?: string
showPreview?: boolean
showToolbar?: boolean
placeholder?: string
}
Example:
import { createFormdownEditor } from '@formdown/editor';
const editor = createFormdownEditor(document.getElementById('editor-container'), {
content: '@name: [text required]',
showPreview: true,
showToolbar: true
});
Type Definitions
Core Types
interface Field {
name: string
type: FieldType
label?: string
required?: boolean
placeholder?: string
attributes?: Record<string, any>
validation?: ValidationRules
options?: string[]
allowOther?: boolean
}
type FieldType =
| 'text' | 'email' | 'password' | 'tel' | 'url' | 'number'
| 'date' | 'time' | 'datetime-local' | 'month' | 'week'
| 'textarea' | 'select' | 'radio' | 'checkbox' | 'file'
| 'color' | 'range' | 'search' | 'hidden' | 'button'
| 'submit' | 'reset'
interface ValidationRules {
min?: number | string
max?: number | string
minlength?: number
maxlength?: number
step?: number
pattern?: string
accept?: string
}
interface FieldError {
field: string
message: string
}
interface ValidationResult {
isValid: boolean
errors: FieldError[]
}
interface FormDownSchema {
[fieldName: string]: FieldSchema
}
interface FieldSchema {
type: FieldType
label?: string
required?: boolean
defaultValue?: any
position?: number
validation?: ValidationRules
htmlAttributes?: Record<string, any>
layout?: 'inline' | 'vertical'
}
Migration Guide
From Legacy Functions to FormManager
The new FormManager API provides enhanced functionality while maintaining backward compatibility:
Legacy approach:
import { parseFormdown, generateFormHTML } from '@formdown/core';
const parsed = parseFormdown(content);
const html = generateFormHTML(parsed);
Modern approach (recommended):
import { FormManager } from '@formdown/core';
const manager = new FormManager();
manager.parse(content);
const html = manager.render();
// Plus: reactive data binding, events, validation, etc.
Benefits of FormManager
- Reactive Data Binding: Automatic synchronization between form data and UI
- Event-Driven Architecture: Subscribe to form events for real-time updates
- Built-in Validation: Schema-based validation with error handling
- State Management: Track dirty state, reset to defaults, export/import configuration
- Type Safety: Full TypeScript support with comprehensive type definitions
Best Practices
1. Use FormManager for Interactive Forms
For forms that require user interaction, validation, or data management:
import { FormManager } from '@formdown/core';
const manager = new FormManager();
manager.parse(formContent);
// Set up event listeners
manager.on('data-change', ({ field, value }) => {
console.log(`Field ${field} changed to:`, value);
});
// Render with current data
const html = manager.render();
2. Use FormdownFieldHelper for DOM Manipulation
When working with rendered forms in the browser:
import { FormdownFieldHelper } from '@formdown/core';
// Get values
const priority = FormdownFieldHelper.get('priority');
// Set values (handles "other" options automatically)
FormdownFieldHelper.set('skills', ['JavaScript', 'Custom Skill']);
// Check specific values
if (FormdownFieldHelper.has('skills', 'Python')) {
// Python is selected
}
3. Validate Before Submission
Always validate form data before processing:
const validation = manager.validate();
if (!validation.isValid) {
validation.errors.forEach(error => {
console.error(`${error.field}: ${error.message}`);
});
return;
}
const data = manager.getData();
// Process valid data...
4. Handle "Other" Options Consistently
The FormdownFieldHelper automatically handles "other" options:
// Formdown syntax with other option
const content = '@priority{Low,Medium,High,*(Custom Priority)}: r[]';
// Setting a custom value automatically uses the other option
FormdownFieldHelper.set('priority', 'Urgent'); // Uses "Custom Priority" option
5. Use Web Components for Quick Integration
For rapid prototyping or simple integrations:
<!-- Include the UI component -->
<script type="module" src="@formdown/ui"></script>
<!-- Use directly in HTML -->
<formdown-ui content="@name: [text required]
@email: [email required]">
</formdown-ui>