Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Angular Signals

ASecurity

Covers Angular Signals in depth: the full reactive primitives system (signal, computed, effect, linkedSignal, resource, rxResource), signal-based component APIs (input, output, model, viewChild, viewChildren, contentChild, contentChildren), zoneless change detection and Zone.js migration, RxJS interop (toSignal, toObservable), state management patterns, Signal Forms, and signal diagnostics. Use for \"Angular signals\", \"signal()\", \"computed()\", \"effect()\", \"linkedSignal\", \"resource a...

4 stars
0 votes
0 copies
0 views
Added 9/24/2026
developmenttypescriptreactangulardebugginggitapi

Works with

api

Security Analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned 9/24/2026

$npx -y skills add chrishuffman5/domain-expert --skill angular-signals --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Angular Signals?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Angular Signals
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/chrishuffman5-angular-signals/badge)](https://www.skillsdirectory.com/skills/chrishuffman5-angular-signals)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: angular-signals
description: "Covers Angular Signals in depth: the full reactive primitives system (signal, computed, effect, linkedSignal, resource, rxResource), signal-based component APIs (input, output, model, viewChild, viewChildren, contentChild, contentChildren), zoneless change detection and Zone.js migration, RxJS interop (toSignal, toObservable), state management patterns, Signal Forms, and signal diagnostics. Use for \"Angular signals\", \"signal()\", \"computed()\", \"effect()\", \"linkedSignal\", \"resource angular\", \"rxResource\", \"toSignal\", \"toObservable\", \"signal input\", \"signal query\", \"viewChild signal\", \"zoneless\", \"zoneless migration\", \"Zone.js removal\", \"signal forms\" questions. Do NOT use for general Angular questions (DI, routing, template syntax, RxJS) that don't involve signals -- use the `angular` skill."
license: MIT
---

# Angular Signals

This skill covers Angular's Signals system -- the reactive primitives that power modern Angular applications -- across the full signal lifecycle from v16 (developer preview) through v21 (zoneless default), including:

- Core primitives: `signal()`, `computed()`, `effect()`, `linkedSignal()` (v19+), `resource()`/`rxResource()` (v19+)
- Signal-based component APIs: `input()`, `output()`, `model()`, `viewChild()`, `viewChildren()`, `contentChild()`, `contentChildren()`
- Zoneless change detection: how it works, migration from Zone.js, hybrid strategies
- RxJS interop: `toSignal()`, `toObservable()`, bridging patterns
- State management: signal stores, service patterns, comparison with NgRx
- Signal Forms: experimental form primitives built on signals (v21)
- Diagnostics: common pitfalls, debugging techniques, Angular DevTools signal inspector

## How to Approach Tasks

1. **Classify** the request:
   - **Primitives / API** -- Load `references/architecture.md`
   - **Zoneless Migration** -- Load `references/migration.md`
   - **RxJS Interop** -- Load `references/migration.md` (interop section)
   - **State Management** -- Use signal store patterns in this file
   - **Troubleshooting** -- Use the diagnostics section below

2. **Identify version** -- Signal API stability varies by version:
   - v19: `linkedSignal`, `resource()` experimental
   - v20: all signal APIs stable
   - v21: zoneless default, Signal Forms experimental

3. **Load context** -- Read the relevant reference file for deep knowledge.

4. **Recommend** -- Provide signal-idiomatic solutions. Prefer `computed()` over `effect()` for derived state, `linkedSignal()` over manual reset patterns, `resource()` over effects with HTTP calls.

## Core Primitives

### signal() -- Writable Reactive State

```typescript
import { signal } from '@angular/core';

const count = signal(0);
count();                  // read: 0
count.set(5);             // replace
count.update(n => n + 1); // derive from current
```

Custom equality suppresses unnecessary notifications:

```typescript
const user = signal<User>(
  { id: 1, name: 'Alice' },
  { equal: (a, b) => a.id === b.id }
);
```

Read-only view for service APIs:

```typescript
private _items = signal<CartItem[]>([]);
readonly items = this._items.asReadonly();
```

### computed() -- Derived Reactive State

Lazy, cached, read-only. Recalculates only when signal dependencies change.

```typescript
const firstName = signal('Jane');
const lastName = signal('Doe');
const fullName = computed(() => `${firstName()} ${lastName()}`);
```

Dependencies are tracked per execution path -- conditional reads create dynamic dependency graphs.

**When NOT to use computed():**
- Side effects needed (use `effect()`)
- Write access needed (use `linkedSignal()`)
- Depends on non-signal external state

### effect() -- Side Effects

Runs once immediately, then re-runs when signal dependencies change.

```typescript
effect(() => {
  document.body.className = theme();
});
```

Must be called in an injection context (constructor/field initializer) or with an explicit injector. Use `onCleanup` for teardown.

```typescript
effect((onCleanup) => {
  const sub = interval(1000).subscribe(() => console.log(tick()));
  onCleanup(() => sub.unsubscribe());
});
```

**Do not write signals in effects** -- use `computed()` or `linkedSignal()` for derived state. **Do not make API calls in effects** -- use `resource()`.

### linkedSignal() -- Writable Derived State (v19+)

A writable signal that auto-resets when a source signal changes.

```typescript
const country = signal('US');
const city = linkedSignal(() => getDefaultCity(country()));

city.set('Boston');    // writable override
country.set('CA');     // city resets to default for CA
```

Options object form for preserving previous values:

```typescript
const selected = linkedSignal({
  source: options,
  computation: (newOptions, previous) => {
    if (previous && newOptions.includes(previous.value)) return previous.value;
    return newOptions[0];
  },
});
```

### resource() and rxResource() -- Async Data (v19+)

```typescript
productResource = resource({
  request: this.productId,
  loader: async ({ request: id, abortSignal }) => {
    const res = await fetch(`/api/products/${id}`, { signal: abortSignal });
    return res.json();
  }
});
```

```typescript
import { rxResource } from '@angular/core/rxjs-interop';

productResource = rxResource({
  request: this.productId,
  loader: ({ request: id }) => this.http.get<Product>(`/api/products/${id}`)
});
```

Status values: `idle`, `loading`, `reloading`, `resolved`, `error`, `local`.

## Signal-Based Component APIs

### input() and input.required()

```typescript
name = input<string>('');         // optional with default
userId = input.required<string>(); // required, no default
```

Returns `InputSignal<T>` -- read-only, reactive in computed/effect.

### model() -- Two-Way Binding

```typescript
isExpanded = model(false); // ModelSignal<boolean>
```

Parent: `<app-panel [(isExpanded)]="panelOpen" />`

### output()

```typescript
searched = output<string>();
this.searched.emit(query);
```

### viewChild(), viewChildren()

```typescript
canvas = viewChild<ElementRef<HTMLCanvasElement>>('canvas');
canvasRequired = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');
items = viewChildren(ItemComponent);
```

### contentChild(), contentChildren()

```typescript
icon = contentChild(IconComponent);
tabs = contentChildren(TabComponent);
```

All signal queries update reactively and work naturally in `computed()` and `effect()`.

## State Management with Signals

### Service with Signals (Recommended)

```typescript
@Injectable({ providedIn: 'root' })
export class CartService {
  private _items = signal<CartItem[]>([]);

  readonly items = this._items.asReadonly();
  readonly total = computed(() => this._items().reduce((sum, i) => sum + i.price * i.qty, 0));
  readonly count = computed(() => this._items().reduce((sum, i) => sum + i.qty, 0));
  readonly isEmpty = computed(() => this._items().length === 0);

  addItem(item: CartItem) {
    this._items.update(items => {
      const existing = items.find(i => i.id === item.id);
      if (existing) {
        return items.map(i => i.id === item.id ? { ...i, qty: i.qty + 1 } : i);
      }
      return [...items, { ...item, qty: 1 }];
    });
  }

  removeItem(id: string) {
    this._items.update(items => items.filter(i => i.id !== id));
  }

  clear() { this._items.set([]); }
}
```

### Comparison: Signals vs NgRx vs ComponentStore

| Concern | Signals | NgRx Store | ComponentStore |
|---|---|---|---|
| Boilerplate | Minimal | High | Medium |
| DevTools | Angular DevTools | Redux DevTools | Redux DevTools |
| Time travel | No | Yes | Yes |
| Best for | Local + simple shared state | Large-scale, audit-critical | Component-scoped complex state |
| Bundle impact | Zero (built-in) | ~50KB | ~15KB |

## Effect Patterns

### Legitimate Use Cases

| Use Case | Pattern |
|---|---|
| localStorage sync | Read signal, write to localStorage |
| Analytics tracking | Read signals, call analytics API |
| DOM manipulation | Canvas, video, third-party libraries |
| Third-party library sync | Migration pattern from Zone.js |

### Anti-Patterns

- Writing signals in effects (infinite loop risk)
- API calls in effects (use `resource()`)
- Derived state in effects (use `computed()`)

### untracked()

Read a signal without registering a dependency:

```typescript
effect(() => {
  const log = auditLog();  // tracked dependency
  const userId = untracked(() => currentUser()?.id); // not tracked
});
```

## Common Issues and Diagnostics

### Forgetting () in Templates

```html
<!-- WRONG -->
<span>{{ count }}</span>

<!-- CORRECT -->
<span>{{ count() }}</span>
```

### Writing Signals in computed()

`computed()` must be pure. Signal writes throw at runtime.

### Circular Effect Dependencies

Effects that write to signals read by other effects can create infinite loops. Angular detects some cycles and throws.

### Stale Values in Non-Reactive Context

Reading `doubled()` in a plain method captures the current value -- it is not reactive outside a reactive context (template, computed, effect).

### Memory Leaks from Manual toSignal()

`toSignal()` with `manualCleanup: true` requires explicit cleanup via `DestroyRef`.

### resource() with Null Request

When the request signal returns null/undefined, `resource()` enters idle state. The loader does not run. This is intentional but can be surprising.

### Third-Party Libraries After Removing Zone.js

Libraries calling Angular APIs from outside the zone will not trigger change detection. Fix: `markForCheck()` in the library callback.

## Version History

| Version | Signals Milestone |
|---|---|
| v16 | Developer Preview: `signal()`, `computed()`, `effect()` |
| v17 | Stable core primitives. Signal inputs/queries developer preview |
| v18 | `toSignal()`/`toObservable()` stable. NgRx Signal Store |
| v19 | `resource()`/`rxResource()` introduced. `linkedSignal()` stable. Zoneless stable API |
| v20 | All signal APIs stable. Signal inputs/queries stable. Full signal lifecycle |
| v21 | Zoneless default. Signal Forms (experimental). Migration schematic |

## Reference Files

- `references/architecture.md` -- Signal primitives, computed, effect, linkedSignal, resource, signal inputs/queries
- `references/migration.md` -- Zone.js to zoneless migration, RxJS interop patterns

Attribution

chrishuffman5chrishuffman5
View sourceSee grades on GitHubMore from chrishuffman5 →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Clean Code

Pragmatic coding standards - concise, direct, no over-engineering, no unnecessary comments

304955 votes

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

286712 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Writing Plans

Use when you have a spec or requirements for a multi-step task, before touching code

2927051 votes
View all in development →