angular-forms — angular-forms install angular-forms, ng-utils, community, angular-forms install, ide skills, angular forms api documentation, Claude Code, Cursor, Windsurf

v1.0.0
GitHub

About this Skill

Ideal for Frontend Development Agents specializing in Angular application architecture and type-safe form management. angular-forms is a feature of Angular that provides a reactive forms API for building type-safe, reactive forms with automatic two-way binding and schema-based validation.

Features

Builds type-safe, reactive forms using Angular's Signal Forms API
Provides automatic two-way binding for efficient form management
Supports schema-based validation for robust form validation
Offers reactive field state for dynamic form updates
Uses the @angular/core import for seamless integration

# Core Topics

ROU-Technology ROU-Technology
[0]
[0]
Updated: 3/8/2026

Agent Capability Analysis

The angular-forms skill by ROU-Technology is an open-source community AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance. Optimized for angular-forms install, angular forms api documentation.

Ideal Agent Persona

Ideal for Frontend Development Agents specializing in Angular application architecture and type-safe form management.

Core Value

Enables agents to construct type-safe, reactive forms with automatic two-way binding and schema-based validation using Angular's experimental Signal Forms API. This provides robust form state management and validation capabilities for complex Angular applications.

Capabilities Granted for angular-forms

Building type-safe reactive forms with automatic binding
Implementing schema-based validation for complex forms
Creating experimental Signal Forms in Angular v21+

! Prerequisites & Limits

  • Experimental feature (Angular v21 only)
  • Not recommended for production applications requiring stability
Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

angular-forms

Install angular-forms, an AI agent skill for AI agent workflows and automation. Works with Claude Code, Cursor, and Windsurf with one-command setup.

SKILL.md
Readonly

Angular Signal Forms

Build type-safe, reactive forms using Angular's Signal Forms API. Signal Forms provide automatic two-way binding, schema-based validation, and reactive field state.

Note: Signal Forms are experimental in Angular v21. For production apps requiring stability, see references/form-patterns.md for Reactive Forms patterns.

Basic Setup

typescript
1import { Component, signal } from '@angular/core'; 2import { form, FormField, required, email } from '@angular/forms/signals'; 3 4interface LoginData { 5 email: string; 6 password: string; 7} 8 9@Component({ 10 selector: 'app-login', 11 imports: [FormField], 12 template: ` 13 <form (submit)="onSubmit($event)"> 14 <label> 15 Email 16 <input type="email" [formField]="loginForm.email" /> 17 </label> 18 @if (loginForm.email().touched() && loginForm.email().invalid()) { 19 <p class="error">{{ loginForm.email().errors()[0].message }}</p> 20 } 21 22 <label> 23 Password 24 <input type="password" [formField]="loginForm.password" /> 25 </label> 26 @if (loginForm.password().touched() && loginForm.password().invalid()) { 27 <p class="error">{{ loginForm.password().errors()[0].message }}</p> 28 } 29 30 <button type="submit" [disabled]="loginForm().invalid()">Login</button> 31 </form> 32 `, 33}) 34export class LoginComponent { 35 // Form model - a writable signal 36 loginModel = signal<LoginData>({ 37 email: '', 38 password: '', 39 }); 40 41 // Create form with validation schema 42 loginForm = form(this.loginModel, (schemaPath) => { 43 required(schemaPath.email, { message: 'Email is required' }); 44 email(schemaPath.email, { message: 'Enter a valid email address' }); 45 required(schemaPath.password, { message: 'Password is required' }); 46 }); 47 48 onSubmit(event: Event) { 49 event.preventDefault(); 50 if (this.loginForm().valid()) { 51 const credentials = this.loginModel(); 52 console.log('Submitting:', credentials); 53 } 54 } 55}

Form Models

Form models are writable signals that serve as the single source of truth:

typescript
1// Define interface for type safety 2interface UserProfile { 3 name: string; 4 email: string; 5 age: number | null; 6 preferences: { 7 newsletter: boolean; 8 theme: 'light' | 'dark'; 9 }; 10} 11 12// Create model signal with initial values 13const userModel = signal<UserProfile>({ 14 name: '', 15 email: '', 16 age: null, 17 preferences: { 18 newsletter: false, 19 theme: 'light', 20 }, 21}); 22 23// Create form from model 24const userForm = form(userModel); 25 26// Access nested fields via dot notation 27userForm.name // FieldTree<string> 28userForm.preferences.theme // FieldTree<'light' | 'dark'>

Reading Values

typescript
1// Read entire model 2const data = this.userModel(); 3 4// Read field value via field state 5const name = this.userForm.name().value(); 6const theme = this.userForm.preferences.theme().value();

Updating Values

typescript
1// Replace entire model 2this.userModel.set({ 3 name: 'Alice', 4 email: 'alice@example.com', 5 age: 30, 6 preferences: { newsletter: true, theme: 'dark' }, 7}); 8 9// Update single field 10this.userForm.name().value.set('Bob'); 11this.userForm.age().value.update(age => (age ?? 0) + 1);

Field State

Each field provides reactive signals for validation, interaction, and availability:

typescript
1const emailField = this.form.email(); 2 3// Validation state 4emailField.valid() // true if passes all validation 5emailField.invalid() // true if has validation errors 6emailField.errors() // array of error objects 7emailField.pending() // true if async validation in progress 8 9// Interaction state 10emailField.touched() // true after focus + blur 11emailField.dirty() // true after user modification 12 13// Availability state 14emailField.disabled() // true if field is disabled 15emailField.hidden() // true if field should be hidden 16emailField.readonly() // true if field is readonly 17 18// Value 19emailField.value() // current field value (signal)

Form-Level State

The form itself is also a field with aggregated state:

typescript
1// Form is valid when all interactive fields are valid 2this.form().valid() 3 4// Form is touched when any field is touched 5this.form().touched() 6 7// Form is dirty when any field is modified 8this.form().dirty()

Validation

Built-in Validators

typescript
1import { 2 form, required, email, min, max, 3 minLength, maxLength, pattern 4} from '@angular/forms/signals'; 5 6const userForm = form(this.userModel, (schemaPath) => { 7 // Required field 8 required(schemaPath.name, { message: 'Name is required' }); 9 10 // Email format 11 email(schemaPath.email, { message: 'Invalid email' }); 12 13 // Numeric range 14 min(schemaPath.age, 18, { message: 'Must be 18+' }); 15 max(schemaPath.age, 120, { message: 'Invalid age' }); 16 17 // String/array length 18 minLength(schemaPath.password, 8, { message: 'Min 8 characters' }); 19 maxLength(schemaPath.bio, 500, { message: 'Max 500 characters' }); 20 21 // Regex pattern 22 pattern(schemaPath.phone, /^\d{3}-\d{3}-\d{4}$/, { 23 message: 'Format: 555-123-4567', 24 }); 25});

Conditional Validation

typescript
1const orderForm = form(this.orderModel, (schemaPath) => { 2 required(schemaPath.promoCode, { 3 message: 'Promo code required for discounts', 4 when: ({ valueOf }) => valueOf(schemaPath.applyDiscount), 5 }); 6});

Custom Validators

typescript
1import { validate } from '@angular/forms/signals'; 2 3const signupForm = form(this.signupModel, (schemaPath) => { 4 // Custom validation logic 5 validate(schemaPath.username, ({ value }) => { 6 if (value().includes(' ')) { 7 return { kind: 'noSpaces', message: 'Username cannot contain spaces' }; 8 } 9 return null; 10 }); 11});

Cross-Field Validation

typescript
1const passwordForm = form(this.passwordModel, (schemaPath) => { 2 required(schemaPath.password); 3 required(schemaPath.confirmPassword); 4 5 // Compare fields 6 validate(schemaPath.confirmPassword, ({ value, valueOf }) => { 7 if (value() !== valueOf(schemaPath.password)) { 8 return { kind: 'mismatch', message: 'Passwords do not match' }; 9 } 10 return null; 11 }); 12});

Async Validation

typescript
1import { validateHttp } from '@angular/forms/signals'; 2 3const signupForm = form(this.signupModel, (schemaPath) => { 4 validateHttp(schemaPath.username, { 5 request: ({ value }) => `/api/check-username?u=${value()}`, 6 onSuccess: (response: { taken: boolean }) => { 7 if (response.taken) { 8 return { kind: 'taken', message: 'Username already taken' }; 9 } 10 return null; 11 }, 12 onError: () => ({ 13 kind: 'networkError', 14 message: 'Could not verify username', 15 }), 16 }); 17});

Conditional Fields

Hidden Fields

typescript
1import { hidden } from '@angular/forms/signals'; 2 3const profileForm = form(this.profileModel, (schemaPath) => { 4 hidden(schemaPath.publicUrl, ({ valueOf }) => !valueOf(schemaPath.isPublic)); 5});
html
1@if (!profileForm.publicUrl().hidden()) { 2 <input [formField]="profileForm.publicUrl" /> 3}

Disabled Fields

typescript
1import { disabled } from '@angular/forms/signals'; 2 3const orderForm = form(this.orderModel, (schemaPath) => { 4 disabled(schemaPath.couponCode, ({ valueOf }) => valueOf(schemaPath.total) < 50); 5});

Readonly Fields

typescript
1import { readonly } from '@angular/forms/signals'; 2 3const accountForm = form(this.accountModel, (schemaPath) => { 4 readonly(schemaPath.username); // Always readonly 5});

Form Submission

typescript
1import { submit } from '@angular/forms/signals'; 2 3@Component({ 4 template: ` 5 <form (submit)="onSubmit($event)"> 6 <input [formField]="form.email" /> 7 <input [formField]="form.password" /> 8 <button type="submit" [disabled]="form().invalid()">Submit</button> 9 </form> 10 `, 11}) 12export class LoginComponent { 13 model = signal({ email: '', password: '' }); 14 form = form(this.model, (schemaPath) => { 15 required(schemaPath.email); 16 required(schemaPath.password); 17 }); 18 19 onSubmit(event: Event) { 20 event.preventDefault(); 21 22 // submit() marks all fields touched and runs callback if valid 23 submit(this.form, async () => { 24 await this.authService.login(this.model()); 25 }); 26 } 27}

Arrays and Dynamic Fields

typescript
1interface Order { 2 items: Array<{ product: string; quantity: number }>; 3} 4 5@Component({ 6 template: ` 7 @for (item of orderForm.items; track $index; let i = $index) { 8 <div> 9 <input [formField]="item.product" placeholder="Product" /> 10 <input [formField]="item.quantity" type="number" /> 11 <button type="button" (click)="removeItem(i)">Remove</button> 12 </div> 13 } 14 <button type="button" (click)="addItem()">Add Item</button> 15 `, 16}) 17export class OrderComponent { 18 orderModel = signal<Order>({ 19 items: [{ product: '', quantity: 1 }], 20 }); 21 22 orderForm = form(this.orderModel, (schemaPath) => { 23 applyEach(schemaPath.items, (item) => { 24 required(item.product, { message: 'Product required' }); 25 min(item.quantity, 1, { message: 'Min quantity is 1' }); 26 }); 27 }); 28 29 addItem() { 30 this.orderModel.update(m => ({ 31 ...m, 32 items: [...m.items, { product: '', quantity: 1 }], 33 })); 34 } 35 36 removeItem(index: number) { 37 this.orderModel.update(m => ({ 38 ...m, 39 items: m.items.filter((_, i) => i !== index), 40 })); 41 } 42}

Displaying Errors

html
1<input [formField]="form.email" /> 2 3@if (form.email().touched() && form.email().invalid()) { 4 <ul class="errors"> 5 @for (error of form.email().errors(); track error) { 6 <li>{{ error.message }}</li> 7 } 8 </ul> 9} 10 11@if (form.email().pending()) { 12 <span>Validating...</span> 13}

Styling Based on State

html
1<input 2 [formField]="form.email" 3 [class.is-invalid]="form.email().touched() && form.email().invalid()" 4 [class.is-valid]="form.email().touched() && form.email().valid()" 5/>

Reset Form

typescript
1async onSubmit() { 2 if (!this.form().valid()) return; 3 4 await this.api.submit(this.model()); 5 6 // Clear interaction state 7 this.form().reset(); 8 9 // Clear values 10 this.model.set({ email: '', password: '' }); 11}

For Reactive Forms patterns (production-stable), see references/form-patterns.md.

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is angular-forms?

Ideal for Frontend Development Agents specializing in Angular application architecture and type-safe form management. angular-forms is a feature of Angular that provides a reactive forms API for building type-safe, reactive forms with automatic two-way binding and schema-based validation.

How do I install angular-forms?

Run the command: npx killer-skills add ROU-Technology/ng-utils/angular-forms. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for angular-forms?

Key use cases include: Building type-safe reactive forms with automatic binding, Implementing schema-based validation for complex forms, Creating experimental Signal Forms in Angular v21+.

Which IDEs are compatible with angular-forms?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for angular-forms?

Experimental feature (Angular v21 only). Not recommended for production applications requiring stability.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add ROU-Technology/ng-utils/angular-forms. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use angular-forms immediately in the current project.

Related Skills

Looking for an alternative to angular-forms or another community skill for your workflow? Explore these related open-source skills.

View All

widget-generator

Logo of f
f

f.k.a. Awesome ChatGPT Prompts. Share, discover, and collect prompts from the community. Free and open source — self-host for your organization with complete privacy.

149.6k
0
AI

flags

Logo of vercel
vercel

flags is a Next.js feature management skill that enables developers to efficiently add or modify framework feature flags, streamlining React application development.

138.4k
0
Browser

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI