Angular Developer Guide
This skill comes from ECC. Keep clear credit to the original author and project.
When to Use This Skill
Use this skill when you:
- Work in an Angular project.
- Create an Angular app or library.
- Create a component, service, directive, pipe, guard, or resolver.
- Use signals,
linkedSignal,resource, oreffect. - Work with Angular forms.
- Set up dependency injection or routes.
- Add lazy loading, SSR, or hydration.
- Add ARIA, styles, or animation.
- Write or fix Angular tests.
- Use the Angular CLI or Angular MCP server.
First Steps
Before giving advice or changing code:
- Find the Angular version.
- Check
package.json. - Run
ng versionif commands are allowed. - If neither works, ask for the version.
- Check
- Check the current project style.
- Standalone or NgModule.
- Current form type.
- Test tool.
- CSS tool.
- Use features that work with that Angular version.
- Keep the current project style unless the user asks to change it.
Do not guess that a new Angular feature is present.
Main Rules
- Follow the Angular style guide.
- Favor small parts with one clear job.
- Use strict TypeScript types.
- Do not use
anyunless there is no safe choice. - Keep templates simple.
- Put shared work in a service or plain helper.
- Use the Angular CLI to make files when it is available.
- Do not replace hand-made project rules without a clear need.
- Do not add a package when Angular already has a good built-in tool.
- Do not make network calls unless the user asks for them.
After code changes:
- Run the smallest useful tests.
- Run
ng build. - Fix errors caused by the change.
- If commands cannot run, say what the user should run.
- Do not claim the build passed unless it ran and passed.
Create a New Project
Use the latest stable Angular version unless the user names a version.
Choose the command with these rules:
If the user asks for a set version, use:
npx @angular/cli@<version> new <project-name>If no version is named, run:
ng versionIf
ng versionworks, use:ng new <project-name>If
ng versionfails because the CLI is missing, use:npx @angular/cli@latest new <project-name>
Before running ng new, confirm choices that change the app in a large way, such as:
- App or library.
- Routing.
- CSS, SCSS, or another style type.
- SSR.
- Test tool.
- Project folder.
If the user gave these choices already, do not ask again.
Components
Read only the files needed for the task:
- Core parts and template flow: components.md
- Inputs, input changes, and model inputs: inputs.md
- Outputs and custom events: outputs.md
- Host bindings and host data: host-elements.md
Use the official component guide only when these files do not answer the task:
https://angular.dev/guide/components
Keep these rules in mind:
- Use clear input and output names.
- Do not change input data inside a child part.
- Use
trackin@forwith a stable key. - Handle empty, loading, and error states.
- Use native HTML controls when they fit.
- Keep direct DOM work rare. Use Angular tools when possible.
Signals and Data
Use Angular signals for local state when the project version supports them.
Read:
signal,computed,untracked: signals-overview.md- State linked to another signal: linked-signal.md
- Async signal data: resource.md
- Side effects and render work: effects.md
Rules:
- Use
computed()for values made from other state. - Use
effect()only for real side effects. - Do not use
effect()to copy state from one signal to another. - Clean up timers, listeners, and streams.
- Show loading, error, empty, and retry states for async data.
- Avoid calls that can race. Cancel or ignore old work when needed.
- Do not use
resourceif the project version does not support it.
Forms
First check the Angular version and the form style already in use.
Choose a form type like this:
- Use signal forms for a new form only when the Angular version supports them and the project accepts that API.
- Match the current form style in an old app.
- Use template-driven forms for small, simple forms.
- Use reactive forms for large forms or apps that already use them.
Read:
- Signal forms: signal-forms.md
- Template-driven forms: template-driven-forms.md
- Reactive forms: reactive-forms.md
For every form:
- Add labels and clear help text.
- Show useful error text.
- Do not show errors before the user can act on them.
- Block double submit.
- Keep server errors separate from field errors.
- Keep user input after a failed submit when safe.
- Use the right input type and browser auto-fill name.
- Make keyboard use work.
Dependency Injection
Read the file that fits the task:
- Main ideas and
inject(): di-fundamentals.md - Create and use services: creating-services.md
- Tokens and provider types: defining-providers.md
- Valid places for
inject(): injection-context.md - Injector levels and lookup rules: hierarchical-injectors.md
Rules:
- Use
providedIn: 'root'for one app-wide service when that scope fits. - Use a local provider when each part needs its own service state.
- Use
InjectionTokenfor values and interfaces. - Do not call
inject()outside an injection context. - Use
runInInjectionContextonly when it is truly needed. - Watch for state leaks when a service lives longer than a component.
Routing and Rendering
Read:
- Route paths and redirects: define-routes.md
- Lazy loading: loading-strategies.md
- Route outlets: show-routes-with-outlets.md
- Links and code-based travel: navigate-to-routes.md
- Route guards: route-guards.md
- Data resolvers: data-resolvers.md
- Router events: router-lifecycle.md
- CSR, pre-render, SSR, and hydration: rendering-strategies.md
- Route view animation: route-animations.md
More help:
https://angular.dev/guide/routing
Rules:
- Put fixed routes before broad routes.
- Put the wildcard route last.
- Lazy-load large feature areas.
- Do not use a client route guard as the only security check.
- Check access again on the server.
- Keep resolvers fast and handle failure.
- Avoid browser-only APIs during SSR.
- Guard use of
window,document, storage, and layout APIs. - Make server and client output match to avoid hydration errors.
- Use pre-render only for paths known at build time.
ARIA and Access
For custom accordion, listbox, combo box, menu, tabs, toolbar, tree, or grid parts, read:
Rules:
- Use native HTML before making a custom control.
- Give every control an accessible name.
- Keep focus clear and visible.
- Support keyboard use.
- Do not add ARIA that fights native HTML.
- Link error text to its field.
- Test focus order and screen reader names.
- Meet color contrast needs.
- Respect reduced motion settings.
Styles and Animation
Read:
- Tailwind CSS setup: tailwind-css.md
- CSS and old Angular animation tools: angular-animations.md
- Component styles and style scope: component-styling.md
Rules:
- Favor CSS for simple motion.
- Use the old Angular animation API only when the project needs it.
- Keep styles near the part they serve.
- Use shared design values for color, space, and type.
- Test small and large screens.
- Do not hide focus outlines without a clear replacement.
- Avoid motion that blocks input or causes harm.
Tests
Read:
- Unit tests and
TestBed: testing-fundamentals.md - Component harnesses: component-harnesses.md
- Router tests: router-testing.md
- Cypress or Playwright: e2e-testing.md
Rules:
- Match the test tool already used by the project.
- Test what the user can see or do.
- Avoid tests tied to private fields.
- Test success, failure, loading, and empty states.
- Use
RouterTestingHarnessfor route tests when it fits. - Keep tests stable. Do not depend on real time or real network calls.
- Add a test for each fixed bug when practical.
Tools
Read:
Use the CLI when it fits:
ng generate component user-card
ng generate service users
ng generate guard auth
ng build
ng testBefore using a command:
- Check the current folder.
- Check the Angular version.
- Check the project name in a multi-project workspace.
- Do not overwrite a file with user changes.
- Do not use a force flag unless the user asks and the risk is clear.
Common Mistakes
Do not:
- Use
nullorundefinedas a signal form field value when'',0, or[]fits. - Write
form.field.valid()when the API needsform.field().valid(). - Start a new form with an old API when signal forms are supported and chosen for the project.
- Set
min,max,value,disabled, orreadonlyon a[formField]input when these rules belong in the signal form schema. - Call
inject()outside an injection context. - Use
effect()for derived state. Usecomputed(). - Use
$parent.$indexin nested@forblocks. Angular does not support$parent. - Track list rows by their index when rows can move, sort, or be removed.
- Put secrets or access checks only in browser code.
- Touch
windowordocumentwithout an SSR-safe check. - Subscribe without cleanup.
- Mix form types in one form without a clear need.
- Add ARIA roles to native controls that already have the right role.
- Claim a build or test passed when it was not run.
For a nested loop, save the outer index with an alias:
@for (group of groups(); track group.id; let groupIndex = $index) {
@for (item of group.items; track item.id) {
<p>Group {{ groupIndex + 1 }}: {{ item.name }}</p>
}
}Concrete Example
User request:
Add a user list page. Load users from a service. Show loading and error text. Add a route and tests.
Work plan:
- Read
package.jsonand runng version. - Check how the app makes components, routes, services, and tests.
- Read the signal, routing, and test files needed for this task.
- Generate files with the same project style.
- Use signals only if the Angular version supports the needed API.
- Add loading, error, empty, and success views.
- Add a stable
track user.idrule to the user loop. - Add route and component tests.
- Run the tests and
ng build. - Report the files changed and any command that could not run.
Example template:
@if (loading()) {
<p role="status">Loading users...</p>
} @else if (error()) {
<p role="alert">{{ error() }}</p>
<button type="button" (click)="loadUsers()">Try again</button>
} @else if (users().length === 0) {
<p>No users found.</p>
} @else {
<ul>
@for (user of users(); track user.id) {
<li>{{ user.name }}</li>
}
</ul>
}Before using this code, confirm that the project supports this template syntax and follows the same state style.