diff --git a/templates/angular/.editorconfig b/templates/angular/.editorconfig
new file mode 100644
index 000000000..f166060da
--- /dev/null
+++ b/templates/angular/.editorconfig
@@ -0,0 +1,17 @@
+# Editor configuration, see https://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.ts]
+quote_type = single
+ij_typescript_use_double_quotes = false
+
+[*.md]
+max_line_length = off
+trim_trailing_whitespace = false
diff --git a/templates/angular/.gitignore b/templates/angular/.gitignore
new file mode 100644
index 000000000..3c7acc57d
--- /dev/null
+++ b/templates/angular/.gitignore
@@ -0,0 +1,49 @@
+# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
+
+# Compiled output
+/dist
+/tmp
+/out-tsc
+/bazel-out
+
+# Node
+/node_modules
+npm-debug.log
+yarn-error.log
+
+# IDEs and editors
+.idea/
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# Visual Studio Code
+.vscode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+.history/*
+
+# Miscellaneous
+/.angular/cache
+.sass-cache/
+/connect.lock
+/coverage
+/libpeerconnection.log
+testem.log
+/typings
+
+# System files
+.DS_Store
+Thumbs.db
+
+#.output
+.output
+
+.angular
+.wxt
diff --git a/templates/angular/README.md b/templates/angular/README.md
new file mode 100644
index 000000000..84d422ed8
--- /dev/null
+++ b/templates/angular/README.md
@@ -0,0 +1,7 @@
+# WXT + Angular
+
+This template should help get you started developing with Angular in WXT.
+
+# WXT
+
+https://github.com/wxt-dev/wxt
diff --git a/templates/angular/angular.json b/templates/angular/angular.json
new file mode 100644
index 000000000..429bc127f
--- /dev/null
+++ b/templates/angular/angular.json
@@ -0,0 +1,73 @@
+{
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "version": 1,
+ "newProjectRoot": "projects",
+ "projects": {
+ "wxt-angular": {
+ "projectType": "application",
+ "schematics": {},
+ "root": "",
+ "sourceRoot": "entrypoints",
+ "prefix": "app",
+ "architect": {
+ "build": {
+ "builder": "@angular/build:application",
+ "options": {
+ "outputPath": {
+ "base": ".output",
+ "browser": ""
+ },
+ "browser": "entrypoints/popup/main.ts",
+ "index": "entrypoints/popup/index-for-ng.html",
+ "tsConfig": "tsconfig.app.json",
+ "assets": [
+ {
+ "glob": "**/*",
+ "input": "public"
+ }
+ ],
+ "styles": ["entrypoints/popup/styles.css"]
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kB",
+ "maximumError": "1MB"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "4kB",
+ "maximumError": "8kB"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "optimization": false,
+ "extractLicenses": false,
+ "sourceMap": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "builder": "@angular/build:dev-server",
+ "configurations": {
+ "production": {
+ "buildTarget": "wxt-angular:build:production"
+ },
+ "development": {
+ "buildTarget": "wxt-angular:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "builder": "@angular/build:extract-i18n"
+ }
+ }
+ }
+ }
+}
diff --git a/templates/angular/entrypoints/background.ts b/templates/angular/entrypoints/background.ts
new file mode 100644
index 000000000..f96fa4804
--- /dev/null
+++ b/templates/angular/entrypoints/background.ts
@@ -0,0 +1,3 @@
+export default defineBackground(() => {
+ console.log('Hello background!', { id: browser.runtime.id });
+});
diff --git a/templates/angular/entrypoints/content.ts b/templates/angular/entrypoints/content.ts
new file mode 100644
index 000000000..264a52820
--- /dev/null
+++ b/templates/angular/entrypoints/content.ts
@@ -0,0 +1,6 @@
+export default defineContentScript({
+ matches: ['*://*.google.com/*'],
+ main() {
+ console.log('Hello content.');
+ },
+});
diff --git a/templates/angular/entrypoints/popup/app.config.ts b/templates/angular/entrypoints/popup/app.config.ts
new file mode 100644
index 000000000..426a77e5d
--- /dev/null
+++ b/templates/angular/entrypoints/popup/app.config.ts
@@ -0,0 +1,12 @@
+import {
+ ApplicationConfig,
+ provideBrowserGlobalErrorListeners,
+ provideZonelessChangeDetection,
+} from '@angular/core';
+
+export const appConfig: ApplicationConfig = {
+ providers: [
+ provideBrowserGlobalErrorListeners(),
+ provideZonelessChangeDetection(),
+ ],
+};
diff --git a/templates/angular/entrypoints/popup/app.css b/templates/angular/entrypoints/popup/app.css
new file mode 100644
index 000000000..818492e41
--- /dev/null
+++ b/templates/angular/entrypoints/popup/app.css
@@ -0,0 +1,43 @@
+:host {
+ display: block;
+ max-width: 1280px;
+ margin: 0 auto;
+ padding: 2rem;
+ text-align: center;
+}
+
+.logo {
+ height: 6em;
+ padding: 1.5em;
+ will-change: filter;
+ transition: filter 300ms;
+}
+.logo:hover {
+ filter: drop-shadow(0 0 2em #54bc4ae0);
+}
+.logo.angular:hover {
+ filter: drop-shadow(0 0 2em #61dafbaa);
+}
+
+@keyframes logo-spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ a:nth-of-type(2) .logo {
+ animation: logo-spin infinite 20s linear;
+ }
+}
+
+.card {
+ padding: 2em;
+}
+
+.read-the-docs {
+ color: #888;
+}
diff --git a/templates/angular/entrypoints/popup/app.html b/templates/angular/entrypoints/popup/app.html
new file mode 100644
index 000000000..6f1ddd9db
--- /dev/null
+++ b/templates/angular/entrypoints/popup/app.html
@@ -0,0 +1,14 @@
+
+WXT + Angular
+
+
+
Edit entrypoints/app.ts
and save to test HMR
+
+Click on the WXT and Angular logos to learn more
diff --git a/templates/angular/entrypoints/popup/app.ts b/templates/angular/entrypoints/popup/app.ts
new file mode 100644
index 000000000..a0f06136e
--- /dev/null
+++ b/templates/angular/entrypoints/popup/app.ts
@@ -0,0 +1,14 @@
+import { Component, signal } from '@angular/core';
+
+@Component({
+ selector: 'app-root',
+ templateUrl: './app.html',
+ styleUrl: './app.css',
+})
+export class App {
+ public count = signal(0);
+
+ public increment() {
+ this.count.update((value) => value + 1);
+ }
+}
diff --git a/templates/angular/entrypoints/popup/index-for-ng.html b/templates/angular/entrypoints/popup/index-for-ng.html
new file mode 100644
index 000000000..5f8bed701
--- /dev/null
+++ b/templates/angular/entrypoints/popup/index-for-ng.html
@@ -0,0 +1,12 @@
+
+
+
+
+ WxtAngular - ng
+
+
+
+
+
+
+
diff --git a/templates/angular/entrypoints/popup/index.html b/templates/angular/entrypoints/popup/index.html
new file mode 100644
index 000000000..040aefc7c
--- /dev/null
+++ b/templates/angular/entrypoints/popup/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+ WxtAngular - wxt
+
+
+
+
+
+
+
+
+
diff --git a/templates/angular/entrypoints/popup/main.ts b/templates/angular/entrypoints/popup/main.ts
new file mode 100644
index 000000000..985d837d9
--- /dev/null
+++ b/templates/angular/entrypoints/popup/main.ts
@@ -0,0 +1,5 @@
+import { bootstrapApplication } from '@angular/platform-browser';
+import { App } from './app';
+import { appConfig } from './app.config';
+
+bootstrapApplication(App, appConfig).catch((err) => console.error(err));
diff --git a/templates/angular/entrypoints/popup/styles.css b/templates/angular/entrypoints/popup/styles.css
new file mode 100644
index 000000000..5384832ef
--- /dev/null
+++ b/templates/angular/entrypoints/popup/styles.css
@@ -0,0 +1,69 @@
+:root {
+ font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-text-size-adjust: 100%;
+}
+
+a {
+ font-weight: 500;
+ color: #646cff;
+ text-decoration: inherit;
+}
+a:hover {
+ color: #535bf2;
+}
+
+body {
+ margin: 0;
+ display: flex;
+ place-items: center;
+ min-width: 340px;
+ min-height: 100vh;
+}
+
+h1 {
+ font-size: 3.2em;
+ line-height: 1.1;
+}
+
+button {
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ background-color: #1a1a1a;
+ cursor: pointer;
+ transition: border-color 0.25s;
+}
+button:hover {
+ border-color: #646cff;
+}
+button:focus,
+button:focus-visible {
+ outline: 4px auto -webkit-focus-ring-color;
+}
+
+@media (prefers-color-scheme: light) {
+ :root {
+ color: #213547;
+ background-color: #ffffff;
+ }
+ a:hover {
+ color: #747bff;
+ }
+ button {
+ background-color: #f9f9f9;
+ }
+}
diff --git a/templates/angular/package.json b/templates/angular/package.json
new file mode 100644
index 000000000..d8a5df8c3
--- /dev/null
+++ b/templates/angular/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "wxt-angular",
+ "version": "0.0.0",
+ "scripts": {
+ "start:ng": "ng serve",
+ "dev": "wxt",
+ "dev:firefox": "wxt -b firefox",
+ "build": "wxt build",
+ "build:firefox": "wxt build -b firefox",
+ "zip": "wxt zip",
+ "zip:firefox": "wxt zip -b firefox",
+ "compile": "tsc --noEmit",
+ "postinstall": "wxt prepare"
+ },
+ "private": true,
+ "dependencies": {
+ "@angular/common": "^20.0.0",
+ "@angular/compiler": "^20.0.0",
+ "@angular/core": "^20.0.0",
+ "@angular/forms": "^20.0.0",
+ "@angular/platform-browser": "^20.0.0",
+ "@angular/router": "^20.0.0",
+ "rxjs": "~7.8.0",
+ "tslib": "^2.3.0"
+ },
+ "devDependencies": {
+ "@analogjs/vite-plugin-angular": "^1.17.1",
+ "@angular/build": "^20.0.2",
+ "@angular/cli": "^20.0.2",
+ "@angular/compiler-cli": "^20.0.0",
+ "typescript": "~5.8.2",
+ "wxt": "^0.20.7"
+ }
+}
diff --git a/templates/angular/public/angular.svg b/templates/angular/public/angular.svg
new file mode 100644
index 000000000..33a106e9c
--- /dev/null
+++ b/templates/angular/public/angular.svg
@@ -0,0 +1 @@
+
diff --git a/templates/angular/public/favicon.ico b/templates/angular/public/favicon.ico
new file mode 100644
index 000000000..57614f9c9
Binary files /dev/null and b/templates/angular/public/favicon.ico differ
diff --git a/templates/angular/public/icon/128.png b/templates/angular/public/icon/128.png
new file mode 100644
index 000000000..9e35d1307
Binary files /dev/null and b/templates/angular/public/icon/128.png differ
diff --git a/templates/angular/public/icon/16.png b/templates/angular/public/icon/16.png
new file mode 100644
index 000000000..cd09f8cfb
Binary files /dev/null and b/templates/angular/public/icon/16.png differ
diff --git a/templates/angular/public/icon/32.png b/templates/angular/public/icon/32.png
new file mode 100644
index 000000000..f51ce1b5c
Binary files /dev/null and b/templates/angular/public/icon/32.png differ
diff --git a/templates/angular/public/icon/48.png b/templates/angular/public/icon/48.png
new file mode 100644
index 000000000..cb7a4494a
Binary files /dev/null and b/templates/angular/public/icon/48.png differ
diff --git a/templates/angular/public/icon/96.png b/templates/angular/public/icon/96.png
new file mode 100644
index 000000000..c28ad52d5
Binary files /dev/null and b/templates/angular/public/icon/96.png differ
diff --git a/templates/angular/public/wxt.svg b/templates/angular/public/wxt.svg
new file mode 100644
index 000000000..0e763206b
--- /dev/null
+++ b/templates/angular/public/wxt.svg
@@ -0,0 +1,15 @@
+
diff --git a/templates/angular/tsconfig.app.json b/templates/angular/tsconfig.app.json
new file mode 100644
index 000000000..02e1d7874
--- /dev/null
+++ b/templates/angular/tsconfig.app.json
@@ -0,0 +1,7 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+ "extends": "./tsconfig.json",
+ "include": ["entrypoints/**/*.ts"],
+ "exclude": ["entrypoints/background.ts", "entrypoints/content.ts"]
+}
diff --git a/templates/angular/tsconfig.json b/templates/angular/tsconfig.json
new file mode 100644
index 000000000..719889395
--- /dev/null
+++ b/templates/angular/tsconfig.json
@@ -0,0 +1,26 @@
+/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
+/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
+{
+ "compileOnSave": false,
+ "compilerOptions": {
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true,
+ "skipLibCheck": true,
+ "isolatedModules": true,
+ "experimentalDecorators": true,
+ "importHelpers": true,
+ "target": "ES2022",
+ "module": "preserve"
+ },
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "typeCheckHostBindings": true,
+ "strictTemplates": true
+ },
+ "files": []
+}
diff --git a/templates/angular/wxt.config.ts b/templates/angular/wxt.config.ts
new file mode 100644
index 000000000..b73b9030c
--- /dev/null
+++ b/templates/angular/wxt.config.ts
@@ -0,0 +1,13 @@
+import { defineConfig } from 'wxt';
+import angular from '@analogjs/vite-plugin-angular';
+
+export default defineConfig({
+ vite: () => ({
+ plugins: [
+ angular({
+ transformFilter: (_, id) =>
+ !(id.endsWith('background.ts') || id.endsWith('content.ts')),
+ }),
+ ],
+ }),
+});