# Angular Component Generator

> Generates a modern Angular standalone component using signals, OnPush change detection, native control flow, and the latest Angular conventions. Use when the user asks to create, scaffold, or generate an Angular component.

- Skill: `brianmtreese/angular-component-generator` (Agent Skill)
- Install (CLI): `npx skillmds@latest add brianmtreese/angular-component-generator`
- Raw SKILL.md: https://api.skillmd.com/api/skills/brianmtreese/angular-component-generator/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: brianmtreese (https://skillmd.com/u/brianmtreese)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/brianmtreese/angular-component-generator

---


# Angular Component Generator

Creates a single, modern Angular component file that follows current Angular (v20+) conventions.

## Conventions to Follow

- **Standalone** - do NOT set `standalone: true` (it's the default in v20+)
- **Change detection** - always set `changeDetection: ChangeDetectionStrategy.OnPush`
- **Inputs / outputs** - use `input()` and `output()` functions, not decorators
- **State** - use `signal()` for local state, `computed()` for derived state
- **Templates** - prefer inline `template`; use `@if` / `@for` / `@switch` (not `*ngIf` / `*ngFor` / `*ngSwitch`)
- **Bindings** - use `class.x` and `style.x` bindings (not `ngClass` / `ngStyle`)
- **Host** - put host bindings/listeners in the `host` object (not `@HostBinding` / `@HostListener`)
- **Injection** - use the `inject()` function, not constructor injection
- **Selector** - kebab-case with an `app-` prefix (e.g. `app-user-card`)
- **File name** - `<name>.component.ts` in `src/app/<name>/`
- **Class name** - PascalCase ending in `Component` (e.g. `UserCardComponent`)

## Workflows

1. Confirm the component name with the user (if not provided) and derive:
   - Folder: `src/app/<kebab-name>/`
   - File: `<kebab-name>.component.ts`
   - Selector: `app-<kebab-name>`
   - Class: `<PascalName>Component`
2. Generate the file using the template below.
3. Only create a separate `.html` / `.css` file if the template or styles are large enough to justify it; otherwise keep them inline.

## Template

```ts
import { ChangeDetectionStrategy, Component, input, output, signal, computed } from '@angular/core';

@Component({
  selector: 'app-<kebab-name>',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <section class="<kebab-name>">
      <h2>{{ title() }}</h2>

      @if (hasItems()) {
        <ul>
          @for (item of items(); track item) {
            <li>{{ item }}</li>
          }
        </ul>
      } @else {
        <p>No items yet.</p>
      }

      <button type="button" (click)="select.emit(title())">Select</button>
    </section>
  `,
  styles: `
    .<kebab-name> { display: block; }
  `,
})
export class <PascalName>Component {
  readonly title = input.required<string>();
  readonly items = input<readonly string[]>([]);

  readonly select = output<string>();

  protected readonly hasItems = computed(() => this.items().length > 0);
  protected readonly isBusy = signal(false);
}
```

## Example

**Request:** "Create a `user-card` component with a `name` input and a `selected` output."

**Output file:** `src/app/user-card/user-card.component.ts`

```ts
import { ChangeDetectionStrategy, Component, input, output } from '@angular/core';

@Component({
  selector: 'app-user-card',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <article class="user-card">
      <h3>{{ name() }}</h3>
      <button type="button" (click)="selected.emit(name())">Select</button>
    </article>
  `,
  styles: `
    .user-card { display: block; padding: 0.5rem; }
  `,
})
export class UserCardComponent {
  readonly name = input.required<string>();
  readonly selected = output<string>();
}
```

## Don'ts

- Don't add `standalone: true`
- Don't use `NgModule`
- Don't use `@Input()` / `@Output()` decorators
- Don't use `*ngIf` / `*ngFor` / `*ngSwitch`
- Don't use `ngClass` / `ngStyle`
- Don't inject via the constructor
- Don't import `CommonModule` just to use control flow (native blocks don't need it)

