angular
Frameworkangular/angular
A TypeScript-based platform for building scalable web applications.
Overview
Angular is a modern, open-source web application framework. It provides a comprehensive suite of tools for building mobile and desktop web applications, including components, forms, routing, and server-side rendering.
README Preview
Angular - The modern web developer's platform\n\n\n \n \n Angular is a development platform for building mobile and desktop web applications\n using TypeScript/JavaScript and other languages.\n \n\n\n\n angular.dev\n \n\n\n\n Contributing Guidelines\n ·\n Submit an Issue\n ·\n Blog\n \n \n\n\n\n \n \n \n\n\n\n\n## Documentation\n\nGet started with Angular, learn the fundamentals and explore advanced topics on our documentation website.\n\n- [Getting Started][quickstart]\n- [Architecture][architecture]\n- [Components and Templates][componentstemplates]\n- [Forms][forms]\n- [API][api]\n\n### Advanced\n\n- [Angular Elements][angularelements]\n- [Server Side Rendering][ssr]\n- [Schematics][schematics]\n- [Lazy Loading][lazyloading]\n- [Animations][animations]\n\n### Local Development\n\nTo contribute to the Angular Docs, check out the [Angular.dev README](adev/README.md)\n\n## Development Setup\n\n### Prerequisites\n\n- Install [Node.js] which includes [Node Package Manager][npm]\n\n### Setting Up a Project\n\nInstall the Angular CLI globally:\n\n```\nnpm install -g @angular/cli\n```\n\nCreate a workspace:\n\n```\nng new [PROJECT NAME]\n```\n\nRun the application:\n\n```\ncd [PROJECT NAME]\nng serve\n```\n\nAngular is cross-platform, fast, scalable, has incredible tooling, and is loved by millions.\n\n## Quickstart\n\n[Get started in 5 minutes][quickstart].\n\n## Ecosystem\n\n\n \n\n\n- [Angular Command Line (CLI)][cli]\n- [Angular Material][angularmaterial]\n\n## Changelog\n\n[Learn about the latest improvements][changelog].\n\n## Upgrading\n\nCheck out our [upgrade guide](https://angular.dev/update-guide/) to find out the best way to upgrade your project.\n\n## Contributing\n\n### Contributing Guidelines\n\nRead through our [contributing guidelines][contributing] to learn about our submission process, coding rules, and more.\n\n### Want to Help?\n\nWant to report a bug, contribute some code, or improve the documentation? Excellent! Read up on ou
FAQ (5)
TroubleshootingWhy does an SVG inside an Angular @if, @for, or @switch block go to the default ng-content slot instead of matching select="svg"?
This is an Angular compiler bug affecting SVG or MathML elements that are the root node of a control-flow block. Angular generates a namespaced tag such as :svg:svg, so it does not match an ng-content tag selector like select="svg" and the element is projected into the default slot.
Workaround: add ngProjectAs to the root SVG or MathML element:
@if (saving()) {
<svg class="spinner" ngProjectAs="svg">...</svg>
} @else {
<svg ngProjectAs="svg">...</svg>
}
For MathML, use:
<math ngProjectAs="math">...</math>
The same workaround applies to @for, @switch, and *ngIf root nodes. Attribute and class selectors are not affected. A permanent fix is provided in the Angular compiler PR; upgrade Angular once a release containing the fix is available.
TroubleshootingWhy do Angular library components stop re-rendering (empty/stale view) in Storybook, Jest, Vitest or TestBed after upgrading to Angular 22?
Cause: Angular 22's JIT path (ɵɵngDeclareComponent → convertDeclareComponentFacadeToMetadata) ignores the declared library version and defaults changeDetection to OnPush, while the AOT linker correctly keeps components compiled with Angular < 22 on Default/Eager. Libraries compiled with partial mode before v22 (e.g., Kendo UI for Angular compiled with Angular 20.3) may assign state inside subscriptions without markForCheck(), so in JIT-based tools (Storybook, jest-preset-angular, Vitest, TestBed, ng serve --aot=false) the view never refreshes, while the AOT build works fine. Workaround: patch the JIT compiler facade before any library declaration is evaluated (e.g., in your Storybook preview setup or test setup file):
import '@angular/compiler';
import { ChangeDetectionStrategy } from '@angular/core';
const facade = (globalThis as any).ng?.ɵcompilerFacade;
const original = facade.compileComponentDeclaration.bind(facade);
facade.compileComponentDeclaration = (env: unknown, url: string, decl: any) => {
const major = Number.parseInt(String(decl.version ?? '0').split('.')[0], 10);
const patched =
decl.changeDetection == null && major > 0 && major < 22
? { ...decl, changeDetection: ChangeDetectionStrategy.Eager }
: decl;
return original(env, url, patched);
};
Alternatively, set changeDetection: ChangeDetectionStrategy.Default explicitly in the library's components and republish with Angular 22. Track the fix in angular/angular#71107.
TroubleshootingWhy is ICU plural text duplicated after Angular SSR hydration with withI18nSupport()?
This is a known Angular bug (issue #71425) affecting provideClientHydration(withI18nSupport()). When the same component with an ICU expression (e.g. {count, plural, ...}) appears multiple times on a page, the server deduplicates hydration data so both instances share the same ngh object. The client then mutates the shared ICU case queue with shift(), so only the first instance hydrates correctly — later instances render the ICU content twice (production) or throw ASSERTION ERROR: expected matching nodeType [Expected=> 8 == 3 <=Actual] (dev mode).
**Workaround:** Replace the ICU expression with control flow and separate i18n messages:
@if (count === 1) {
<ng-container i18n>1 item</ng-container>
} @else {
<ng-container i18n>{{ count }} items</ng-container>
}
This avoids the shared ICU case queue entirely. The bug exists in Angular 18.2 through at least 21.2/22.x, so upgrading does not help — use the workaround until the fix lands (the proposed fix copies the case queue with [...caseQueue] instead of mutating the shared serialized data).
TroubleshootingHow to fix Angular NG0904 'Unsafe value used in a resource URL context' when binding an iframe src?
NG0904 occurs when a plain string is bound to a resource URL property such as <iframe [src]>. Calling sanitize(SecurityContext.URL, url) is insufficient for resource URLs; Angular requires an explicitly trusted SafeResourceUrl.
Fix it with bypassSecurityTrustResourceUrl:
import { Component, inject } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
@Component({
selector: 'app-root',
template: `<iframe [src]="trustedUrl"></iframe>`,
})
export class App {
readonly url = 'data:image/svg+xml;base64,...';
private readonly sanitizer = inject(DomSanitizer);
readonly trustedUrl: SafeResourceUrl =
this.sanitizer.bypassSecurityTrustResourceUrl(this.url);
}
Only use this for URLs you trust, especially data: URLs or user-provided URLs. For untrusted input, validate it against an allowlist or do not bind it to a resource URL.
TroubleshootingHow to fix Angular DevTools showing the home root route as active on nested routes?
This is a known Angular DevTools route-highlighting bug: when viewing a nested URL such as /posts/1, the root route / is incorrectly marked as active even though it is not the active route. It was fixed in angular/angular#65037.
To resolve it:
1. Update the Angular DevTools browser extension.
- Chrome/Edge: open chrome://extensions, enable Developer mode, click **Update**, then reopen DevTools.
- Firefox: update Angular DevTools from about:addons.
2. If running DevTools locally, pull the latest code and rebuild:
git pull origin main
npm install
npm startAlternatively, cherry-pick or merge PR #65037.
No application routing change is required. Until updated, treat the active badge on / as a display-only bug and verify the current route with Router.url or router events.