@kedevked/json-schema-form
v0.0.2
Published
Render a fully reactive, signal-based Angular form from a JSON Schema string.
Maintainers
Readme
@kedevked/json-schema-form
An Angular library that renders a fully reactive, signal-based form directly from a JSON Schema string. Built on top of Angular Signal Forms.
Features
- Renders
object,string,number,integer,boolean, andenumfields from a JSON Schema - Nested objects with recursive rendering
- Built-in validation:
required,minLength,maxLength,minimum,maximum,enum - Conditional fields via
if/then/elseanddependentRequired - Fully customizable field components for each field kind
- No built-in submit button, so you keep full control over form shell and actions
Installation
npm install @kedevked/json-schema-formPeer dependencies:
@angular/common^22.0.0@angular/core^22.0.0@angular/forms^22.0.0
Quick start
import { Component } from '@angular/core';
import { JsonSchemaForm, type JsonSchemaFormModel } from '@kedevked/json-schema-form';
@Component({
standalone: true,
imports: [JsonSchemaForm],
template: `
<form (ngSubmit)="formRef.submit()">
<json-schema-form #formRef [schema]="schema" (formSubmit)="onSubmit($event)" />
<button type="submit">Submit</button>
</form>
`,
})
export class MyComponent {
schema = JSON.stringify({
type: 'object',
required: ['name'],
properties: {
name: { type: 'string', title: 'Name' },
age: { type: 'integer', title: 'Age', minimum: 0, maximum: 120 },
},
});
onSubmit(value: JsonSchemaFormModel) {
console.log(value);
}
}Component API
Inputs
| Input | Type | Description |
|---|---|---|
| schema (required) | string | JSON Schema document as a string. Changing it rebuilds the form from scratch. |
| field | FieldTree<JsonSchemaFormModel> | Use when embedding into an externally owned Signal Form. |
| fieldComponents | Partial<JsonSchemaFieldComponentRegistry> | Per-instance field renderer overrides. |
| validators | Partial<JsonSchemaValidatorRegistry> | Per-instance validator overrides. |
Outputs
| Output | Type | Description |
|---|---|---|
| valueChange | OutputRef<JsonSchemaFormModel> | Emits current form value on every change. |
| formSubmit | OutputRef<JsonSchemaFormModel> | Emits value when submit() is called and form is valid. |
Methods
submit(): validates and emitsformSubmitonly when valid.
Naming and app semantics
submit() is intentionally low-level and generic. In app code, wrap it with your
own domain-specific naming (for example saveProfile(), publish(), continue()).
Use valueChange as the source of truth for the current model in your component.
import { Component, signal } from '@angular/core';
import { JsonSchemaForm, type JsonSchemaFormModel } from '@kedevked/json-schema-form';
@Component({
standalone: true,
imports: [JsonSchemaForm],
template: `
<json-schema-form
#formRef
[schema]="schema"
(valueChange)="currentValue.set($event)"
(formSubmit)="submitted.set($event)"
/>
<button type="button" (click)="saveProfile(formRef)">Save profile</button>
`,
})
export class MyComponent {
schema = '{"type":"object","properties":{"name":{"type":"string"}}}';
currentValue = signal<JsonSchemaFormModel | null>(null);
submitted = signal<JsonSchemaFormModel | null>(null);
saveProfile(form: JsonSchemaForm): void {
form.submit();
}
}## Headless usage (no renderer components)
If you only want schema parsing, default model creation, and Signal Forms validation
without using `<json-schema-form>`, use `createJsonSchemaFormState()`.
```ts
import { Component } from '@angular/core';
import { FormField } from '@angular/forms/signals';
import { createJsonSchemaFormState } from '@kedevked/json-schema-form';
@Component({
standalone: true,
imports: [FormField],
template: `
<form (ngSubmit)="submit()">
<input type="text" [formField]="state.fields.name" />
<label>
<input type="checkbox" [formField]="state.fields.subscribed" />
Subscribed
</label>
<button type="submit">Submit</button>
</form>
`,
})
export class HeadlessFormComponent {
readonly state = createJsonSchemaFormState(
JSON.stringify({
type: 'object',
required: ['name'],
properties: {
name: { type: 'string' },
subscribed: { type: 'boolean' },
},
}),
);
submit(): void {
if (this.state.fields().valid()) {
console.log(this.state.fields().value());
}
}
}
```
This pattern gives you complete control over layout and interactions while reusing
the package's schema normalization, default-value model generation, and validators.
If you call `createJsonSchemaFormState()` outside an Angular injection context,
pass `{ injector }` explicitly.Supported JSON Schema keywords
| Keyword | Applies to | Effect |
|---|---|---|
| type | all | Selects field component type |
| title | all | Field label |
| description | all | Available in field view model |
| required | object | Marks listed properties as required |
| default | all | Initial value |
| enum | string, number | Restricts values to allowed options |
| minLength / maxLength | string | String length validation |
| minimum / maximum | number, integer | Numeric range validation |
| properties | object | Nested object field definitions |
| if / then / else | object | Conditional required fields |
| dependentRequired | object | Field dependencies |
Customizing field components
Register globally:
import { provideJsonSchemaFieldComponents } from '@kedevked/json-schema-form';
import { MyStringField, MyNumberField } from './my-fields';
export const appConfig = {
providers: [
provideJsonSchemaFieldComponents({
string: MyStringField,
number: MyNumberField,
}),
],
};Or override per instance:
<json-schema-form [schema]="schema" [fieldComponents]="myComponents" />Development
pnpm install
npx nx test json-schema-form
npx nx build json-schema-formLicense
MIT
