{"id":51377213,"url":"https://github.com/mspas/forge-form","last_synced_at":"2026-07-05T21:00:33.614Z","repository":{"id":348977674,"uuid":"1178775661","full_name":"mspas/forge-form","owner":"mspas","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-15T12:49:53.000Z","size":142,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-15T14:14:34.021Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mspas.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-11T11:02:04.000Z","updated_at":"2026-06-15T12:49:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mspas/forge-form","commit_stats":null,"previous_names":["mspas/schema-form-engine","mspas/forge-form"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/mspas/forge-form","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mspas%2Fforge-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mspas%2Fforge-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mspas%2Fforge-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mspas%2Fforge-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mspas","download_url":"https://codeload.github.com/mspas/forge-form/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mspas%2Fforge-form/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35168795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-05T02:00:06.290Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-03T14:00:27.945Z","updated_at":"2026-07-05T21:00:33.607Z","avatar_url":"https://github.com/mspas.png","language":"TypeScript","funding_links":[],"categories":["Third Party Components"],"sub_categories":["Forms"],"readme":"# @forge-form/angular\r\n\r\nSchema-driven, signal-based reactive forms for Angular. Describe your form as a\r\nplain TypeScript object and let the engine build the `FormGroup`, render the\r\nfields, wire up validation, hints, error messages, and conditional visibility.\r\n\r\n- **Schema-first** — define controls, groups, validators, and layout declaratively.\r\n- **Signal-based** — built on Angular signals with `OnPush` change detection.\r\n- **Reactive Forms under the hood** — emits a strongly-typed value on submit.\r\n- **Extensible** — custom error and hint components, theming via SCSS.\r\n- **Standalone** — no NgModules required.\r\n\r\n## Requirements\r\n\r\n| Peer dependency   | Version   |\r\n| ----------------- | --------- |\r\n| `@angular/core`   | `^21.2.0` |\r\n| `@angular/common` | `^21.2.0` |\r\n| `@angular/forms`  | `^21.2.0` |\r\n| `rxjs`            | `^7.8.0`  |\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install @forge-form/angular\r\n```\r\n\r\n## Quick start\r\n\r\nImport `FormRendererComponent`, pass it a schema, and handle the typed\r\n`formSubmit` output.\r\n\r\n```ts\r\nimport { Component } from '@angular/core';\r\nimport { FormRendererComponent, FormSchema, required, minLength } from '@forge-form/angular';\r\n\r\ninterface UserModel {\r\n  firstName: string;\r\n  age: number;\r\n}\r\n\r\n@Component({\r\n  selector: 'app-user-form',\r\n  imports: [FormRendererComponent],\r\n  template: `\r\n    \u003cforge-form-angular [schema]=\"schema\" (formSubmit)=\"onSubmit($event)\" /\u003e\r\n  `,\r\n})\r\nexport class UserFormComponent {\r\n  schema: FormSchema = {\r\n    updateOn: 'blur',\r\n    options: { orientation: 'column', theme: 'default' },\r\n    controls: [\r\n      {\r\n        type: 'text',\r\n        controlName: 'firstName',\r\n        label: 'First name',\r\n        placeholder: 'Enter your first name',\r\n        validators: [required(), minLength({ value: 3 })],\r\n      },\r\n      {\r\n        type: 'number',\r\n        controlName: 'age',\r\n        label: 'Age',\r\n        validators: [required()],\r\n      },\r\n    ],\r\n  };\r\n\r\n  onSubmit(value: UserModel) {\r\n    console.log('Submitted', value);\r\n  }\r\n}\r\n```\r\n\r\n### Reading live value and validity\r\n\r\n`FormRendererComponent` exposes `value` and `valid` signals, readable via a\r\ntemplate reference variable without waiting for submit:\r\n\r\n```html\r\n\u003cforge-form-angular #userForm [schema]=\"schema\" (formSubmit)=\"onSubmit($event)\" /\u003e\r\n\r\n\u003cpre\u003e{{ userForm.value() | json }}\u003c/pre\u003e\r\n\u003cspan\u003eValid: {{ userForm.valid() }}\u003c/span\u003e\r\n```\r\n\r\n## Styling\r\n\r\nThe package ships SCSS files. Import them once in your global stylesheet to get\r\nthe default layout and theme:\r\n\r\n```scss\r\n// styles.scss\r\n@use '@forge-form/angular/styles' as forge;\r\n@use '@forge-form/angular/styles/default' as forge-theme;\r\n```\r\n\r\nTo enable the default theme, set `theme: 'default'` in the schema's `options`.\r\nYou can also skip the theme and style the `forge-*` CSS classes yourself.\r\n\r\nInvalid, touched/dirty controls get an error class so you can style them even\r\nwithout the default theme: `forge-form-input-error` on text/number/select\r\ninputs, `forge-form-checkbox-error` on checkboxes.\r\n\r\n## Schema reference\r\n\r\n### `FormSchema`\r\n\r\n| Property   | Type                                    | Description                            |\r\n| ---------- | --------------------------------------- | -------------------------------------- |\r\n| `controls` | `(GroupFieldSchema \\| ControlSchema)[]` | Top-level controls and groups.         |\r\n| `id`       | `string`                                | Optional form id.                      |\r\n| `updateOn` | `'change' \\| 'blur' \\| 'submit'`        | When control values/validation update. |\r\n| `options`  | `FormOptions`                           | Layout, theme, and submit button.      |\r\n\r\n### `FormOptions`\r\n\r\n| Property           | Type                  | Description                                                                  |\r\n| ------------------ | --------------------- | ---------------------------------------------------------------------------- |\r\n| `orientation`      | `'column' \\| 'row'`   | Layout of top-level controls.                                                |\r\n| `labelOrientation` | `'column' \\| 'row'`   | Default label placement, overridable per control.                            |\r\n| `theme`            | `'none' \\| 'default'` | Activates the bundled default theme.                                         |\r\n| `hideSubmitButton` | `boolean`             | Hides the built-in submit button, e.g. to provide your own outside the form. |\r\n\r\n### Control types\r\n\r\nAll controls share `controlName`, `label`, `options`, `initialValue`,\r\n`validators`, `visibility`, `updateOn`, and `hint`.\r\n\r\n| `type`     | Extra properties                           |\r\n| ---------- | ------------------------------------------ |\r\n| `text`     | `placeholder`                              |\r\n| `number`   | `placeholder`, `min`, `max`                |\r\n| `checkbox` | —                                          |\r\n| `select`   | `items: { label, value }[]`, `placeholder` |\r\n\r\n### Groups\r\n\r\nNest controls with a `group`:\r\n\r\n```ts\r\n{\r\n  type: 'group',\r\n  options: { orientation: 'row' },\r\n  controls: [\r\n    { type: 'text', controlName: 'firstName', label: 'First' },\r\n    { type: 'text', controlName: 'lastName', label: 'Last' },\r\n  ],\r\n}\r\n```\r\n\r\n## Validators\r\n\r\nHelper functions return a `ValidatorSchema`:\r\n\r\n```ts\r\nimport { required, minLength, maxLength, min, max, customValidator } from '@forge-form/angular';\r\n\r\nvalidators: [\r\n  required(),\r\n  minLength({ value: 3, errorMessage: 'Name is too short' }),\r\n  customValidator({\r\n    key: 'mustAccept',\r\n    fn: (control) =\u003e (control.value === true ? null : { mustAccept: true }),\r\n    errorMessage: 'You must accept the terms',\r\n  }),\r\n];\r\n```\r\n\r\nEach validator accepts an optional `errorMessage` that can be a string, a\r\nfunction of the validation error, or a custom component definition.\r\n\r\n## Conditional visibility\r\n\r\n```ts\r\nvisibility: {\r\n  fn: (ctx) =\u003e ctx.form.get('firstName')?.valid === true,\r\n  behavior: 'hide', // or 'disable'\r\n  clearOnHide: true,\r\n}\r\n```\r\n\r\n## Custom hint and error components\r\n\r\nCustom hint components extend `FormFieldContextComponent`, which exposes\r\n`control`, `controlValue`, `controlErrors`, and `controlSchema` inputs:\r\n\r\n```ts\r\nimport { Component, computed, input } from '@angular/core';\r\nimport { FormFieldContextComponent } from '@forge-form/angular';\r\n\r\n@Component({\r\n  selector: 'app-char-counter',\r\n  template: `\r\n    {{ currentLength() }} / {{ maxLength() }}\r\n  `,\r\n})\r\nexport class CharCounterComponent extends FormFieldContextComponent {\r\n  maxLength = input\u003cnumber\u003e();\r\n  currentLength = computed(() =\u003e (this.controlValue() as string | undefined)?.length ?? 0);\r\n}\r\n```\r\n\r\nReference it from a control's `hint`:\r\n\r\n```ts\r\nhint: {\r\n  component: CharCounterComponent,\r\n  inputs: { maxLength: 100 },\r\n}\r\n```\r\n\r\n## Public API\r\n\r\n`FormRendererComponent`, `FormFieldContextComponent`, schema models\r\n(`FormSchema`, `ControlSchema` variants, `FormOptions`, `VisibilitySchema`, …),\r\nvalidator helpers, DI tokens (`RENDERERS`, `FORM_OPTIONS`, `ERROR_MESSAGES`,\r\n`DEFAULT_ERROR_FALLBACK`), and the error/hint models are exported from the\r\npackage entry point.\r\n\r\n## Building from source\r\n\r\n```bash\r\nng build forge-form-angular   # outputs to dist/forge-form-angular\r\nng test forge-form-angular    # run unit tests\r\n```\r\n\r\n## License\r\n\r\n[MIT](./LICENSE)\r\n\r\n## Additional Resources\r\n\r\nFor more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.\r\n\r\n# Demo app - @forge-form/angular\r\n\r\nThis demo application was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.2.1.\r\n\r\n## Development server\r\n\r\nTo start a local development server, run:\r\n\r\n```bash\r\nng serve\r\n```\r\n\r\nOnce the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.\r\n\r\n## Code scaffolding\r\n\r\nAngular CLI includes powerful code scaffolding tools. To generate a new component, run:\r\n\r\n```bash\r\nng generate component component-name\r\n```\r\n\r\nFor a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:\r\n\r\n```bash\r\nng generate --help\r\n```\r\n\r\n## Building\r\n\r\nTo build the project run:\r\n\r\n```bash\r\nng build\r\n```\r\n\r\nThis will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.\r\n\r\n## Running unit tests\r\n\r\nTo execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command:\r\n\r\n```bash\r\nng test\r\n```\r\n\r\n## Running end-to-end tests\r\n\r\nFor end-to-end (e2e) testing, run:\r\n\r\n```bash\r\nng e2e\r\n```\r\n\r\nAngular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.\r\n\r\n## Additional Resources\r\n\r\nFor more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmspas%2Fforge-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmspas%2Fforge-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmspas%2Fforge-form/lists"}