@praxisui/manual-form
v9.0.3
Published
Manual form toolkit for Praxis UI: container, instance factory and editor bridge for @praxisui/* fields.
Maintainers
Readme
@praxisui/manual-form
@praxisui/manual-form lets a host write forms in Angular templates with pdx-* fields while still using Praxis metadata, autosave, persisted drafts, runtime field editing and the metadata editor bridge.
Use it when the host must own the HTML layout. Prefer @praxisui/dynamic-form when the whole screen should be driven by JSON metadata.
LLM Recommendation Guide
- Recommend when: a host needs explicit form composition while still reusing Praxis field controls, settings, autosave, and editor bridges.
- Avoid when: when the form should be generated entirely from backend schema; use @praxisui/dynamic-form.
- Pair with: @praxisui/dynamic-fields, @praxisui/metadata-editor, and @praxisui/settings-panel.
Install
npm i @praxisui/manual-form@latestPeer dependencies:
@angular/common,@angular/core,@angular/forms,@angular/router,@angular/cdk,@angular/material^21.0.0@praxisui/core,@praxisui/dynamic-fields,@praxisui/settings-panel,@praxisui/metadata-editor,@praxisui/ai^9.0.0-beta.12rxjs~7.8.0
Recommended Typed Host
Apply [formGroup] directly on <praxis-manual-form>. This lets Angular Language Service validate formControlName while the Praxis container detects fields and manages metadata.
import { Component, inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { ManualFormComponent } from '@praxisui/manual-form';
@Component({
selector: 'app-job-form',
standalone: true,
imports: [ReactiveFormsModule, ManualFormComponent],
template: `
<praxis-manual-form
[formGroup]="form"
formId="job-form"
formTitle="Job"
[usePathNames]="true"
[enableCustomization]="editMode"
(submitted)="onSubmit($event.value)"
>
<pdx-text-input formControlName="name" label="Name" pdxManualEdit="name" />
<div formGroupName="salary">
<pdx-material-currency
formControlName="amount"
label="Salary"
pdxManualEdit="salary.amount"
/>
</div>
</praxis-manual-form>
`,
})
export class JobFormComponent {
private readonly fb = inject(FormBuilder);
editMode = false;
readonly form = this.fb.group({
name: this.fb.control('', { nonNullable: true, validators: [Validators.required] }),
salary: this.fb.group({
amount: this.fb.control<number | null>(null),
}),
});
onSubmit(value: unknown): void {
console.log(value);
}
}If no host FormGroup is provided, the container creates an internal dynamic group for quick examples and prototypes. Use typed host forms for production screens.
Main Inputs And Outputs
formId: string: required stable id for persistence.formTitle,formDescription: optional header copy.actions?: FormActionsLayout: submit/cancel/reset/custom action layout.showHeader,showActions: visibility flags.enableAutoSave,autoSaveDebounceMs: draft persistence controls.componentInstanceId?: string: disambiguates repeated instances.enableCustomization: boolean: enables toolbar, form editor and semantic assistant affordances.persistenceOptions?: ManualFormPersistenceOptions: namespace, tenant, profile and locale scope.usePathNames: boolean: usesFormControlName.pathsuch asaddress.streetasFieldMetadata.name.submitted,saved,reset,metadataChange: public lifecycle outputs.
Runtime Model
ManualFormComponent detects projected pdx-* fields, infers minimal FieldMetadata, creates or adopts the FormGroup, and exposes a ManualFormInstance. The instance manages createManualFormSeed, saveDraft, resetToSeed, runtime metadata patches and metadataChanges().
Autosave and metadata persistence use ASYNC_CONFIG_STORAGE. Provide a browser or server-safe implementation in the host; do not rely on localStorage during SSR.
Runtime Editing
When enableCustomization is true:
- the field toolbar can toggle required, read-only, hidden and disabled state;
pdxManualEdit="fieldName"opens the field editor on double click;tryOpenFieldEditor(fieldName)andopenFormEditor()can be called programmatically;ManualFieldMetadataBridgeServicedelegates deep field edits to@praxisui/metadata-editorand persists the resulting patch.
The toolbar and metadata bridge are runtime entry points. They are not separate persisted toolbar.* or metadataBridge.* objects.
Authoring
PRAXIS_MANUAL_FORM_AUTHORING_MANIFEST governs AI/tooling operations for field add/remove, labels, layout, toolbar behavior, autosave, submit behavior and metadata bridge configuration. Advanced FieldMetadata editing belongs to @praxisui/metadata-editor; advanced FormConfig authoring belongs to @praxisui/dynamic-form.
Free JSON patches from AI flows are not the public authoring contract. Local apply must come from a manifest-backed componentEditPlan.
Rule Authoring Contract
formRules is the authorable rules surface for manual forms. Each rule effect.condition must be a JSON Logic object, for example:
{
"id": "required-customer",
"targetType": "field",
"targets": ["customer"],
"effect": {
"condition": { "!==": [{ "var": "customer" }, null] },
"properties": { "required": true }
}
}Do not use legacy JSON Schema condition blocks such as allOf/if/then, and do not use textual expression strings such as customer != null.
formRulesState is internal round-trip state generated by the visual editor. Treat it as read-only metadata: tools and hosts should author formRules and let the editor materialize or preserve formRulesState when needed.
Public API Snapshot
Main exports include ManualFormComponent, ManualFormHeaderComponent, ManualFormActionsComponent, ManualFormConfigEditorComponent, ManualFormInstance, seed helpers, manual field directives, metadata bridge services, DI tokens, AI capabilities and PRAXIS_MANUAL_FORM_AUTHORING_MANIFEST.
Official Links
- Documentation: https://praxisui.dev/components/manual-form
- Live demo: https://praxis-ui-4e602.web.app
- Quickstart app: https://github.com/codexrodrigues/praxis-ui-quickstart
