skills/angular-component-inputs/SKILL.md
Modern function-based component inputs and models using Angular Signals API. Trigger: When defining component inputs, when migrating from decorators, when working with reactive component APIs, when implementing two-way binding.
npx skillsauth add araujomartin/angular-agent-skills angular-component-inputsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Minimum Angular Version: 17.3.0
Maximum Angular Version: 21.0.0
Supported Versions: 17, 18, 19, 20, 21
Note: Signal inputs (
input(),model()) were introduced as developer preview in v17.3. They became stable/production-ready in v19.0.
Load this skill when:
@Input() decorators to function-based APIsmodel()Introduced in: v17.3 (developer preview) | Stable since: v19.0
Use the input() and input.required() functions instead of the @Input() decorator. These create InputSignal objects that integrate seamlessly with Angular's reactivity system.
// ✅ GOOD - Function-based inputs
import { Component, input, ChangeDetectionStrategy } from '@angular/core';
interface User {
id: string;
name: string;
}
@Component({
selector: 'app-user-card',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="user-card">
<h3>{{ user().name }}</h3>
<p>ID: {{ user().id }}</p>
@if (disabled()) {
<span class="badge">Disabled</span>
}
</div>
`
})
export class UserCardComponent {
// Required input - will error if not provided
readonly user = input.required<User>();
// Optional input with default value
readonly disabled = input(false);
// Optional input without default (undefined initially)
readonly userId = input<string>();
}
// ❌ BAD - Old decorator-based approach
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-user-card',
standalone: true,
template: `...`
})
export class UserCardComponent {
@Input({ required: true }) user!: User;
@Input() disabled = false;
@Input() selected = false;
}
Introduced in: v17.3 (developer preview) | Stable since: v19.0
Use the model() function for two-way binding. It creates both the input and its "Change" event automatically, replacing the [(value)] two-way binding pattern with decorators.
// ✅ GOOD - Model for two-way binding
import { Component, model, input, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app-custom-checkbox',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<label>
<input
type="checkbox"
[checked]="checked()"
(change)="toggle()"
/>
{{ label() }}
</label>
`
})
export class CustomCheckboxComponent {
readonly label = input.required<string>();
// Creates both "checked" input and its "checkedChange" event
readonly checked = model(false);
toggle(): void {
this.checked.set(!this.checked());
}
}
Usage in parent:
@Component({
selector: 'app-parent',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CustomCheckboxComponent],
template: `
<!-- Two-way binding -->
<app-custom-checkbox
label="Accept terms"
[(checked)]="termsAccepted"
/>
<!-- Or one-way binding -->
<app-custom-checkbox
label="Subscribe"
[checked]="subscribed"
(checkedChange)="onSubscribeChange($event)"
/>
`
})
export class ParentComponent {
termsAccepted = signal(false);
subscribed = signal(true);
onSubscribeChange(value: boolean): void {
this.subscribed.set(value);
}
}
Introduced in: v17.3 (developer preview) | Stable since: v19.0
Use the alias option to provide a different name for the input property in templates while keeping a different name in the component class.
// ✅ GOOD - Input with alias
import { Component, input, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app-user-profile',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<h2>{{ userName() }}</h2>
`
})
export class UserProfileComponent {
// Template uses "name", component uses "userName"
readonly userName = input.required<string>({ alias: 'name' });
}
Usage:
<!-- Use the alias in templates -->
<app-user-profile name="John Doe" />
For detailed examples and common mistakes, see references/input-patterns.md.
| Task | Pattern |
|------|---------|
| Required input | readonly user = input.required<User>() |
| Optional input with default | readonly disabled = input(false) |
| Optional input without default | readonly userId = input<string>() |
| Input with alias | readonly userName = input.required<string>({ alias: 'name' }) |
| Two-way binding | readonly checked = model(false) |
| Required model | readonly value = model.required<string>() |
| Access input value | this.userName() |
| Update model | this.checked.set(true) |
documentation
Creates new AI agent skills for Angular following the Angular Agent Skills spec. Trigger: When user asks to create a new skill, add agent instructions, document Angular patterns for AI, or create skill documentation.
development
Recommended usage of access modifiers in Angular components: public readonly for API (inputs/outputs), protected readonly for template state, private readonly for internal logic. Trigger: When defining component properties in Angular.
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.