@ngx-json-forms/core
v1.21.1
Published
JSON-driven Angular form engine. Build dynamic, reactive Angular forms from a JSON config — validation, conditional fields (showWhen), computed values, multi-step wizard, FormArray repeaters, persistence — without writing template code. Pair with @ngx-jso
Maintainers
Keywords
Readme
@ngx-json-forms/core
Build any Angular form from a JSON config — validation, conditional logic, computed values, wizards and repeaters, with zero template code.
🖥 Live demo · ⚡ Try on StackBlitz · 📦 Source
Install — one command for everything (PrimeNG renderer)
ng add @ngx-json-forms/primengThat installs @ngx-json-forms/core + @ngx-json-forms/primeng plus
PrimeNG, the Aura theme, primeicons and animations, and wires
provideNgxJsonFormsPrimeng() into your app.config.ts. Angular ≥ 21.2.
Already using a different UI kit? npm i @ngx-json-forms/core and write
your own adapter (the core is UI-agnostic).
@ngx-json-forms/core is the UI-agnostic brain of ngx-json-forms. Hand it an
array of FormField definitions and it builds a fully reactive Angular FormGroup
for you — with validation, conditional visibility, computed fields, wizard state,
FormArray repeaters and persistence — without any UI dependencies.
Pair it with a renderer adapter such as
@ngx-json-forms/primeng
to render the form, or write your own.
Why use it?
- Forms become data. A
FormField[]is JSON — store it, version it, A/B-test it, or fetch it from your backend and render a different form per tenant. No redeploy to change a form. - Stop hand-wiring
FormGroups. No morenew FormGroup({...}), manual validators,valueChangessubscriptions, or*ngIfspaghetti for conditional fields. - Batteries included. Cross-field validators, async validators, computed/derived fields, multi-step wizards, repeaters and auto-save are first-class — not things you re-invent on every project.
- Bring your own UI. The engine emits a plain reactive
FormGroup; the renderer is swappable. Use the PrimeNG adapter or build one for your design system. - Standards-friendly. Already have a JSON Schema? Convert it to fields with one
call (
formFieldsFromJsonSchema).
Try it before you install
| | |
|---|---|
| 🖥 Live demo | raghav-pal-dev.github.io/ngx-json-forms — browse every field with a live preview + copy-paste config |
| ⚡ StackBlitz | fork the playground — edit catalog.ts, watch the form re-render instantly. No install. |
Install
npm i @ngx-json-forms/corePeer dependencies: @angular/core, @angular/forms, rxjs (all ≥ 19).
Quick start
import { Component, inject } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { FormEngineService, FormField, presets } from '@ngx-json-forms/core';
@Component({
selector: 'app-profile',
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="form">
<input formControlName="firstName" placeholder="First name" />
<input formControlName="email" placeholder="Email" />
<button [disabled]="form.invalid">Save</button>
</form>
`,
})
export class ProfileForm {
private readonly engine = inject(FormEngineService);
// Presets for the common cases, hand-roll the rest:
fields: FormField[] = [
presets.text({ formControlName: 'firstName', label: 'First name', required: true, minLength: 2 }),
presets.email({ formControlName: 'email', label: 'Email' }),
];
form = this.engine.buildFormGroup(this.fields);
}💡 Want the form rendered for you (inputs, validation messages, layout)? Add
@ngx-json-forms/primengand drop in<ngx-json-form [fieldsInput]="fields" />.
One-call wiring (optional)
import { provideNgxJsonForms } from '@ngx-json-forms/core';
export const appConfig = {
providers: [
provideNgxJsonForms({
// storage: myStorageAdapter, // for persistKey auto-save
// translate: (key, params) => i18n.translate(key, params), // localise error text
}),
],
};Granular alternatives: provideFormEngineStorage(adapter), provideFormEngineTranslator(fn).
What's in the box
FormEngineService—buildFormGroup, signal-basedformValue/formValid/patchTick, wizard helpers (nextStep,prevStep,goToStep,validateStep),FormArrayhelpers (addArrayItem,removeArrayItem,moveArrayItem), cross-field validators, computed-field recomputation, andbuildSubmitPayload()that stripstransientfields.FieldRegistry— register custom renderer components, async option loaders, and computed-field functions referenced by string token from JSON.AsyncValidatorRegistry— sync + async validator tokens forvalidations.rules.custom/validations.asyncValidators.FormPersistenceService—bind(form, key)/save/load/clearagainst an injectableStorageAdapter(defaults tolocalStorage).- Conditional visibility / disable via
showWhen/disableWhenwith operatorseq | neq | gt | gte | lt | lte | in | notIn | truthy | falsy | contains | matches. transient— keep a field in the liveFormGroupbut exclude it from the payload.computed— derive a control's value from other controls, live.
Computed fields (inline function)
{
formControlName: 'fullName',
transient: true, // not in the submit payload
computed: {
deps: ['firstName', 'lastName'],
fn: (deps) => `${deps['firstName'] ?? ''} ${deps['lastName'] ?? ''}`.trim(),
},
config: { attributes: { inputType: 'text', readonly: true } },
}computed.fn also accepts a registry token (string) so a computation can be shared
across forms.
From a standard JSON Schema
Already have a JSON Schema (an OpenAPI request body, an Ajv validator, a backend
contract)? Map it to FormField[] automatically:
import { formFieldsFromJsonSchema, JsonSchema } from '@ngx-json-forms/core';
const userSchema: JsonSchema = {
type: 'object',
required: ['email', 'role'],
properties: {
firstName: { type: 'string', title: 'First name', minLength: 2 },
email: { type: 'string', format: 'email', title: 'Email' },
role: { type: 'string', title: 'Role', enum: ['admin', 'editor', 'viewer'] },
},
};
fields = formFieldsFromJsonSchema(userSchema);| JSON Schema | Maps to |
|---------------------------------------------------|-------------------------------|
| string / format: email / password | text / email / password |
| format: date / date-time / time | datePicker / time |
| string, enum | select |
| number / integer | numeric text |
| boolean | toggle |
| array of object / of enum strings | repeater / multiSelect |
| object | group (nested FormGroup) |
| required, minLength, pattern, minimum, … | validations.rules |
Not yet:
allOf/anyOf/oneOf, external$refs, tuple arrays. Pre-flatten withjson-schema-ref-parserfor those.
Custom translations & storage
import { FORM_ENGINE_TRANSLATE, FORM_ENGINE_STORAGE } from '@ngx-json-forms/core';
providers: [
{ provide: FORM_ENGINE_TRANSLATE, useValue: (key, params) => yourI18n.t(key, params) },
{ provide: FORM_ENGINE_STORAGE, useClass: MyStorageAdapter },
]Without a translator, sensible English defaults are used
("{label} is required", "Enter a valid email address", …).
License
MIT © Raghvendrasing Pal
