Angular components — dumb ui, thin containers, logic in stores
SkillDev toolsUse when writing or editing an Angular component in this workspace — presentational (ui) or container components. Covers the clean component rules: dumb ui components, thin containers, and where logic must not go.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Angular components — dumb ui, thin containers, logic in stores skill
What this skill tells your AI
The instructions your AI receives, as published by fabiangosebrink/dog-rate-app in .claude/skills/angular-components/SKILL.md and read by ahel’s review.
Components hold no logic. They bind signals and forward events. Every decision —
data shaping, calculations, navigation, add versus update — lives in a store (see the
state-management skill), never in a component class or template.
Presentational (*/ui) components
Dumb by construction:
standalone,ChangeDetectionStrategy.OnPush.- Inputs via
input()/input.required(), outputs viaoutput(). No@Input/@Outputdecorators. - No injected store and no data services. A ui component depends only on its inputs and
emits via its outputs.
SingleDogComponent(dogin,dogDeletedout) andDogRateComponent(currentDogin,rated/skippedout) are the reference dumb components. - No data fetching, and no derivations beyond trivial display formatting (use pipes like
DecimalPipe/DatePipein the template rather than computing in the class). - Reactive forms live here (the form is UI), but the submit payload is emitted via an
output()— the container store decides what to do with it. Reference:DogFormComponent.
Container (*/feature) components
Thin wiring only:
standalone,OnPush,inject()(never constructor injection).- Inject exactly one local store (provided via
providers: [XStore]on the component), bind its signals into the template, and forward child outputs to store methods or events. Reference:MyDogsComponent,MainDogComponent,DogDetailComponent,AddDogComponent. - No logic in the class or template beyond binding inputs and forwarding events.
- A container may pass a route input signal into an
rxMethod(that is whatrxMethodis for), but the store keeps the resolved plain value, never the signal.DogDetailComponentbinds the route param withdogId = input('')and callsstore.loadSingleDogIfNotLoaded(this.dogId);DogDetailsStorestoresdogId: string | null.
Forms
A form is UI, so it lives entirely in the presentational component; what happens after submit is store work. The form and the store never reference each other.
- The
*/uiform component owns the whole form. The workspace uses signal forms (form()from@angular/forms/signals): the form model, its validators, the photo handling, and the submit guard all live in the ui component. On a valid submit it emits the payload via anoutput()and does nothing else. It imports domain models only — never a store or a service. Reference:DogFormComponent, which emits anAddedDogPayloadthrough itsdogAddedoutput. - The container store handles the result: persistence (delegating to
DogsStore), the success notification, and navigation. Reference:AddDogStore.addDogWithPicture, wired up byAddDogComponent. - They communicate only through the form component's
input()(value in) andoutput()(submit payload out). The store does not know the form exists; the form does not know a store exists.
Everywhere
@if/@for(never*ngIf/*ngFor).- No
subscribe()in components. null, neverundefined, for optional inputs (input<T | null>(null)).- No comments that restate what the code does.
The dogs feature is the reference example. See also the state-management and
angular-signals skills.
Signals
- GitHub stars
- 99
- Forks
- 11
- Last commit
- Jul 2026
Advanced
- Catalog kind
- skill
- Gateway key
angular-components- Source
- github.com/fabiangosebrink/dog-rate-app