Help us improve
Share bugs, ideas, or general feedback.
From flow
Provides examples and guardrails for modern Angular development: standalone components, signals, control flow (@if/@for/@switch), inject services, and Angular 17+ best practices.
npx claudepluginhub cofin/flow --plugin flowHow this skill is triggered — by the user, by Claude, or both
Slash command
/flow:angularThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
<workflow>
Provides expertise for modern Angular v20+ apps using Signals, Standalone Components, Zoneless change detection, SSR/Hydration, and reactive patterns. Ideal for new builds and performance optimization.
Generates Angular code and provides architectural guidance for projects, components, services, signals, forms, DI, routing, SSR, accessibility, animations, styling, testing, and CLI tooling.
Provides expert Angular/TypeScript patterns for standalone components, signals, RxJS, NgRx state management, smart/dumb components, and performance.
Share bugs, ideas, or general feedback.
import { Component, signal, computed, effect, input, output } from '@angular/core';
@Component({
selector: 'app-item-list',
standalone: true,
imports: [],
template: `
<h2>{{ title() }} ({{ count() }})</h2>
<ul>
@for (item of items(); track item.id) {
<li (click)="selectItem(item)">{{ item.name }}</li>
}
</ul>
`
})
export class ItemListComponent {
// Input signals
title = input.required<string>();
items = input.required<Item[]>();
// Output
itemSelected = output<Item>();
// Local state
selected = signal<Item | null>(null);
// Computed
count = computed(() => this.items().length);
constructor() {
effect(() => {
console.log('Selected:', this.selected());
});
}
selectItem(item: Item) {
this.selected.set(item);
this.itemSelected.emit(item);
}
}
<!-- @if -->
@if (loading()) {
<app-spinner />
} @else if (error()) {
<app-error [message]="error()!" />
} @else {
<app-content [data]="data()" />
}
<!-- @for -->
@for (item of items(); track item.id; let i = $index, first = $first) {
<div [class.first]="first">{{ i + 1 }}. {{ item.name }}</div>
} @empty {
<p>No items found</p>
}
<!-- @switch -->
@switch (status()) {
@case ('loading') { <app-spinner /> }
@case ('error') { <app-error /> }
@default { <app-content /> }
}
<!-- @defer -->
@defer (on viewport) {
<app-heavy-component />
} @loading (minimum 200ms) {
<app-skeleton />
}
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { toSignal } from '@angular/core/rxjs-interop';
@Injectable({ providedIn: 'root' })
export class ItemService {
private http = inject(HttpClient);
items = toSignal(this.http.get<Item[]>('/api/items'), {
initialValue: []
});
async create(item: CreateItemDto): Promise<Item> {
return await firstValueFrom(
this.http.post<Item>('/api/items', item)
);
}
}
inject() instead of constructor injection -- More concise, better type inference, and works seamlessly with functional-style code.@if, @for, and @switch instead of structural directives (*ngIf, *ngFor).resource() and httpResource() are experimental -- Use only when the project explicitly accepts experimental APIs; otherwise, use HttpClient with toSignal().@defer -- Use it to lazy load heavy or non-critical components to optimize initial bundle size.
standalone: true@if, @for) is used instead of legacy structural directivessignal, computed, input)inject() function@for loops have a meaningful track expression@defer for lazy loading