https://github.com/ronbodnar/ng-modular-forms
A lightweight architectural layer with built-in components for modular Angular reactive forms.
https://github.com/ronbodnar/ng-modular-forms
angular angular-forms angular-material dynamic-forms forms modular-forms reactive-forms typescript
Last synced: about 14 hours ago
JSON representation
A lightweight architectural layer with built-in components for modular Angular reactive forms.
- Host: GitHub
- URL: https://github.com/ronbodnar/ng-modular-forms
- Owner: ronbodnar
- License: mit
- Created: 2026-04-12T11:28:03.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-06-28T21:28:06.000Z (8 days ago)
- Last Synced: 2026-06-28T23:07:36.877Z (7 days ago)
- Topics: angular, angular-forms, angular-material, dynamic-forms, forms, modular-forms, reactive-forms, typescript
- Language: TypeScript
- Homepage: http://ngmf.ronbodnar.com/
- Size: 958 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- fucking-awesome-angular - ng-modular-forms - A lightweight architectural layer with built-in components for modular Angular reactive forms. (Third Party Components / Forms)
- awesome-angular - ng-modular-forms - A lightweight architectural layer with built-in components for modular Angular reactive forms. (Third Party Components / Forms)
README
ng-modular-forms
A structured Angular forms architecture built for complex, scalable applications.
Live Examples & Interactive Demo →
## The Problem
As enterprise Angular applications grow, form logic quickly becomes a maintenance bottleneck. Side-effect subscriptions spread across components, API data mapping logic gets duplicated, and components bloat with validation mechanics.
## The Solution
`ng-modular-forms` introduces a strict **separation of concerns** layer built right on top of Angular Reactive Forms. It isn't a replacement for standard reactive APIs — it's an architectural framework designed to decouple:
* **Form Orchestration:** Isolate conditional validation and multi-step workflow logic.
* **Reactive Behaviors:** Pull complex cross-field dependencies out of presentation components.
* **Data Mapping:** Translate backend DTOs to form states declaratively.
* **UI Shells:** Interchange native elements and Angular Material layers instantly.
## Key Features
- Typed Reactive Forms support
- Form orchestration layer
- DTO ↔ Form mapping
- State hydration and serialization
- Cross-field behavior management
- Dynamic enable/disable workflows
- Native and Angular Material UI packages
- Consistent component APIs
- Enterprise-scale architecture patterns
- Angular 19–21 support
## Installation & Setup
### 1. Install Packages
Start with core:
```bash
npm install @ng-modular-forms/core
```
If you are using Angular Material components, install the UI adapter and its peer dependencies:
```bash
npm install @ng-modular-forms/material @angular/material @angular/cdk
```
### 2. Configure Global Styles
Add the required control structural themes to your angular.json styles pipeline depending on your configuration:
```json
"styles": [
"src/styles.css",
// Required ONLY if utilizing @ng-modular-forms/core native UI elements
"node_modules/@ng-modular-forms/core/styles/form-controls.css",
// Required ONLY if utilizing @ng-modular-forms/material UI components
"node_modules/@ng-modular-forms/material/styles/form-controls.css"
]
```
### 3. Configure Global Configuration
`@ng-modular-forms/core` provides a single global configuration system via `provideNmfConfig`.
This configuration is shared across all packages (core + material) **and is optional**.
If not provided, sensible defaults are used.
#### Available options
```typescript
translate?: (
key: string,
params?: Record
) => string;
validationMessages?: ValidationMessages;
```
#### Code Example
```typescript
import { ApplicationConfig, inject } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { provideNmfConfig } from '@ng-modular-forms/core';
export const appConfig: ApplicationConfig = {
providers: [
// Simple config
provideNmfConfig({
validationMessages: {
email: 'Invalid email',
},
})
//DI-based config
provideNmfConfigFactory(() => {
const translate = inject(TranslateService);
return {
translate: (k, p) => translate.instant(k, p),
validationMessages: {},
};
});
],
};
```
## Code Examples
### Start Simple
```typescript
@Component({
template: `
`,
})
export class EmployeeComponent {
form = new FormGroup({
firstName: new FormControl('', Validators.required),
salary: new FormControl(null),
});
}
```
Start with standard Angular Reactive Forms and adopt orchestration features only when your application needs them.
### Add Reactive Logic
As forms grow, reactive business rules often end up scattered throughout Angular components.
`ng-modular-forms` allows reactive behavior to be moved into dedicated handlers.
```typescript
@Injectable()
export class RegistrationFormHandler extends FormHandlerBase {
override getReactiveLogic(form?: FormGroup) {
if (!form) {
throw new Error(
'RegistrationFormHandler requires a form instance'
);
}
this.initializeForm(form);
const emailControl =
this.getControl('personalInfo.email');
return this.valueChangesOf(
'preferences.agreeToTerms'
).subscribe((acceptedTerms) => {
const validators = acceptedTerms
? [Validators.required, Validators.email]
: [Validators.email];
emailControl.setValidators(validators);
emailControl.updateValueAndValidity({
emitEvent: false,
});
});
}
}
```
Instead of managing subscriptions inside components, business rules are isolated into reusable handlers that can be tested independently.
### DTO ↔ Form Mapping
API contracts and form models often evolve independently.
`ng-modular-forms` provides dedicated mappers for translating between them.
```typescript
export class PreferencesMapper extends FormMapperBase<
PreferencesDto,
PreferencesForm,
PreferencesForm,
PreferencesOptions
> {
override fromModel(dto: PreferencesDto) {
return {
receiveEmails: dto.receive_emails,
theme: dto.theme_name,
};
}
override toRequest(formValue: PreferencesForm, options?: PreferencesOptions) {
return {
receive_emails: formValue.receiveEmails,
theme: formValue.theme,
};
}
}
```
Mapping logic remains centralized and reusable instead of being duplicated throughout components and services.
### Large Forms and Multi-Step Workflows
As complexity grows, handlers, mappers, hydration, and serialization can be orchestrated through a single coordinator.
```typescript
@Component({
providers: [
MultiStepFormHandler,
PersonalInfoFormHandler,
AccountDetailsFormHandler,
PreferencesFormHandler,
],
})
export class MultiStepFormComponent
extends FormOrchestrator {
initialize() {
this.orchestrate({
form: registrationForm,
handlerRegistry: [
inject(MultiStepFormHandler),
inject(PersonalInfoFormHandler),
inject(AccountDetailsFormHandler),
inject(PreferencesFormHandler),
],
mapperRegistry: {
preferences: new PreferencesMapper(),
},
});
this.hydrateFromModel(existingUser);
}
}
```
The same architecture scales from simple forms to enterprise workflows without moving business logic into Angular components.
## Developer Quick Start
Clone and run the examples app:
```bash
git clone https://github.com/ronbodnar/ng-modular-forms.git
cd ng-modular-forms
npm install
npm start
```
Open your browser to `http://localhost:4200/docs/examples` to see the live interactive examples.
## Ecosystem Packages
Package
Description
Links
@ng-modular-forms/core
Form orchestration, reactive behavior handling, API mapping, and state hydration
npm,
docs
@ng-modular-forms/material
Angular Material-based input components
npm,
docs
## Unified Input Control API
All integrated control primitives are built on ControlValueAccessor. This allows you to interchange Native selectors for Material selectors instantly without altering a single line of orchestration logic.
| Input Type | Native Selector | Material Selector | Description |
|-------------------|--------------------------------|------------------------------------|----------------------------------------------------------|
| Text / Password | `nmf-text` | `nmf-mat-text` | Masking, text parsing, and standard string inputs. |
| Lookup | `nmf-lookup` | `nmf-mat-lookup` | Automated synchronous/asynchronous auto-complete engine. |
| Number / Currency | `nmf-number` | `nmf-mat-number` | Strictly typed runtime numeric normalization. |
| Range Slider | `nmf-range` | Not available | Clamped min/max sliding numeric selection |
| Date | `nmf-datepicker` | `nmf-mat-datepicker` | Calendar utility wrappers. |
| Time | `nmf-timepicker` | `nmf-mat-timepicker` | Standard temporal data picking inputs. |
| Select | `nmf-select` | `nmf-mat-select` | Option-driven stream selectors. |
| Textarea | `nmf-textarea` | `nmf-mat-textarea` | Multi-line textual controls. |
### Features
- `ControlValueAccessor` compatible
- Fully compatible with Angular Reactive Forms
- Consistent API across all inputs
- Built-in validation state + error messaging
- Label, required indicator, and loading state support
- Behavior-driven input handling (formatting, parsing, restrictions)
## License
MIT