home / skills / hoangnguyen0403 / agent-skills-standard / forms

forms skill

/skills/angular/forms

This skill enforces reactive, strictly typed non-nullable forms with FormControl and FormGroup to improve reliability and maintainability.

npx playbooks add skill hoangnguyen0403/agent-skills-standard --skill forms

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
876 B
---
name: Forms
description: Standards for Typed Reactive Forms and Validators.
metadata:
  labels: [angular, forms, reactive-forms, validation]
  triggers:
    files: ['**/*.ts', '**/*.html']
    keywords: [FormBuilder, FormGroup, FormControl, Validators]
---

# Forms

## **Priority: P2 (MEDIUM)**

## Principles

- **Reactive Forms**: Always use Reactive Forms (`FormControl`, `FormGroup`) over Template-Driven Forms for complex inputs.
- **Strict Typing**: Use strictly typed forms `FormGroup<LoginForm>`.
- **Non-Nullable**: Use `nonNullable: true` option to avoid `null` checks on form values.

## Guidelines

- **Component Store integration**: Sync form value changes to Signal Store/Service if needed.
- **Split Logic**: Logic for validation should be in custom validator functions, not inside the component.

## References

- [Typed Forms](references/typed-forms.md)

Overview

This skill documents standards and best practices for building typed, reactive forms and validators in TypeScript-based frameworks. It emphasizes predictable form state, strong typing, and separation of validation logic to improve maintainability and reduce runtime errors. The guidance targets complex input scenarios across web and mobile frameworks where consistent form behavior matters.

How this skill works

The skill prescribes using Reactive Forms primitives (FormControl, FormGroup) with strict TypeScript typing to model form state. It recommends enabling nonNullable form controls to eliminate null checks and locating validation logic in reusable validator functions or services. Optionally, it describes synchronizing form values with a component store or signal-based service when app-wide state or side effects are required.

When to use it

  • Complex forms with dynamic controls, conditional validation, or nested models
  • Applications that require compile-time safety for form values and shape
  • When you need reusable, testable validation logic separated from UI components
  • Integrations that sync form state with centralized stores or side-effect handlers
  • Multi-platform codebases (web, mobile) where consistent form standards reduce bugs

Best practices

  • Prefer Reactive Forms (FormControl/FormGroup) over template-driven approaches for non-trivial forms
  • Declare FormGroup with a typed interface (e.g., FormGroup<LoginForm>) to get type safety
  • Set nonNullable: true on controls to avoid runtime null checks and simplify value access
  • Implement validation in standalone validator functions or services rather than inside components
  • Keep form-to-store synchronization explicit and debounced to avoid performance issues

Example use cases

  • Login form typed as FormGroup<LoginForm> with nonNullable controls and custom password validator
  • Complex checkout flow syncing billing/shipping fields to a component store for autosave
  • Reusable email/phone validators extracted into a validators module used across modules
  • Reactive form wrappers for mobile frameworks (React Native, Flutter/Dart) adopting the same validation rules
  • Onboarding multi-step form with step validation handled by composed validator functions

FAQ

Why prefer Reactive Forms over Template-Driven?

Reactive Forms provide explicit control, easier testing, and better suitability for complex or dynamic form scenarios.

What does nonNullable: true do?

It forces the control value type to exclude null, removing the need for null checks and simplifying TypeScript usage.