# How to Build a Chrome Extension Using Angular

> Learn how to create a Chrome Extension in general and how to build the frontend part of your application using Angular.

- Author: Marius Bongarts
- Published: 2022-11-20
- Updated: 2023-08-09
- Tags: Chrome Extension, Angular, Web Development
- Reading time: 6 min
- URL: https://web-highlights.com/blog/how-to-build-a-chrome-extension-using-angular/

---

Creating your own Chrome Extensions is easier than many may think. And it’s a lot of fun. We can let our creativity run wild and modify each website as we want it to.

In this article, I will show you how to set up a Chrome Extension in general. Afterward, we will set up an Angular application and load it on any website.

> [**How To Build A Chrome Extension Using React**](https://web-highlights.com/blog/how-to-build-a-chrome-extension-using-react/) — Learn how to create a Chrome Extension in general and how to build the frontend part of your application using React. (Marius Bongarts)

### Setup

Before we start, let’s create two subfolders in our repository: **_extension_** and **_angular-chrome-app_** . The **_extension_** folder will contain our chrome extension files, and we will create an Angular app in the **_angular-chrome-app_** directory.

The structure should look like this:

![Repository folder structure](https://cdn-images-1.medium.com/max/1760/1*92hkdAK2ne8AnXmWEFv2gg.png)

*Repository folder structure*

### Chrome Extension Setup

Let’s dive right into the setup of our Chrome extension. First of all, we need to create a `manifest.json` file. We will create the file in our **_extension_** subfolder.

The manifest is the entry point of our extension, which defines metadata, such as name and version, as well as additional functionalities.

#### Create manifest.json

Let’s create a `manifest.json` and add some metadata:

```json
{
  "name": "Angular Chrome Extension",
  "version": "1.0.0",
  "manifest_version": 3
}
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/a0780fffecbb4439a15a5e087ec915cc)

The first three values `name` , `version` and `manifest_version` are sufficient to create our first chrome extension.

#### Install the extension

Open your Chrome browser and navigate to **chrome://extensions** .

Enable Developer Mode by clicking the toggle switch next to **Developer mode** . Click the “ **Load unpacked”** button and select the **_extension_** directory of our repo containing our `manifest.json` .

![Screenshot: How to load unpacked Chrome extension](https://cdn-images-1.medium.com/max/1760/1*W5rm8itxo70rfLrdtd3VKQ.png)

*Load unpacked Chrome extension*

Congratulations! You’ve just created a Chrome Extension!

### Set up Angular application

Now, let’s set up our Angular application in a subfolder of our repository.

We can do this by running:

`npx -p @angular/cli ng new angular-chrome-app`

or just (if you have installed the Angular CLI):

`ng new angular-chrome-app`

Now, let’s eliminate all the unnecessary stuff in the `app.component.html` file. For this article, let’s put a simple _“Hello from Angular App”_ headline to our component:

```html
<div>
  <header>
    <h2>Hello From {{title}} 👋</h2>
  </header>
</div>
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/8f249d5df3e8ac48d9a64172c8626b3d)

```ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  title = 'Angular App';
}
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/09742ad387e31a659a7370c09da6bf73)

As we want to include the Angular app in our Chrome Extension, we need to configure how Angular sets up our application. For that, we need to change the `main.ts` file:

```ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';

const ROOT_ELEMENT_TAG = 'app-root';

let rootElement = document.querySelector(ROOT_ELEMENT_TAG);

if (!rootElement) {
  rootElement = document.createElement(ROOT_ELEMENT_TAG);
  rootElement.id = 'angular-chrome-app';
  document.body.appendChild(document.createElement(ROOT_ELEMENT_TAG));
}

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch((err) => console.error(err));
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/ed147942edf31406dddd929a689fe177)

To use our app on any website, we can not assume anymore that the `<app-root>` element exists that is usually provided by our `index.html` file. That’s why we will create our own root element programmatically before rendering the application.

We check whether there is an existing `<app-root>` element in the DOM. If not, we will create a new one and append it to the document body.

Finally, let’s create some global styles within the `styles.scss` file to position our App visibly on the left side of the screen:

```scss
app-root {
  position: fixed;
  left: 0;
  top: 0;
  width: 300px;
  height: 100vh;
  background: #ffffff;
  border-right: 1px solid #c2c2c2;
  z-index: 999;
}
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/982cb659ebbd6faabd11139a8bd04547)

### Include Angular App into Chrome Extension

In the beginning, we already installed our extension. Still, currently, it doesn’t do anything because we haven’t added functionality to our `manifest.json` .

#### Create a Content Script

To include our Angular App in any webpage, we need a way to read the DOM and make changes to it.

For that, we will create a content script:

> **_Content scripts_** _live in an isolated world, allowing a content script to make changes to its JavaScript environment without conflicting with the page or other extensions’ content Scripts. —_  [developer.chrome.com](https://developer.chrome.com/docs/extensions/mv2/content_scripts/)

For starters, let’s create a `content.js` file with an alert to ensure that our extension successfully loads the script. This file will act as our content script.

```js
alert('Hello world from content.js');
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/cb146c0a1e761e4291d3c0aeb2c67969)

The `content.js` script is the entry point of our extension. Let’s adjust our `manifest.json` to inject our script:

```json
{
  "name": "Angular Chrome Extension",
  "version": "1.0.0",
  "manifest_version": 3,
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": [
        "content.js"
      ]
    }
  ]
}
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/213e9d542e6fbe3d7e56e7212fd4e905)

To use our statically declared `content.js` script we need to register it under the `content_scripts` field. This field needs to define the _required_ attribute `matches` to specify on which pages the content script will be injected. For that, you can set several [match patterns](https://developer.chrome.com/docs/extensions/develop/concepts/match-patterns) . We will use the special pattern `<all_urls>` to match any URL that starts with a permitted scheme- for example `http` or `https` .

We also define the optional field `js` . Here we define our scripts to be injected into matching pages.

Let’s update our extension by pressing the refresh button of the extension on `chrome://extensions` . We can now navigate to any page, and if done correctly, an alert should appear when the page is loaded.

![Screenshot showing alert on Medium.com](https://cdn-images-1.medium.com/max/1760/1*L--jyGGyNT7tWGSDOIMl0A.png)

Worst Chrome Extension ever, right? Let’s continue and include Angular.

#### Create an Angular Content Script

Let’s build our Angular application by running `yarn build` or `npm run build` .

You should see that the react-scripts build script generates some Javascript files in the **_/dist/angular-chrome-app_** folder:

![Screenshot: Angular build folder](https://cdn-images-1.medium.com/max/1760/1*dqETET9_8S-ii2mCpn-pMA.png)

*Angular build folder*

From the generated `index.html` we can derive which files are necessary to make the application work:

```html
<body>
  <app-root></app-root>
  <script src="runtime.b46334b3af268ec4.js" type="module"></script>
  <script src="polyfills.8d28de284ef0dd8f.js" type="module"></script>
  <script src="main.87d969ee394c36a6.js" type="module"></script>
</body>
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/a7c7b61e2a6a317631bceee7f2a4ba14)

We can see that three JavaScript files are loaded to make our Angular application work:

-   **runtime** .\[hash\].js
-   **polyfills** .\[hash\].js
-   **main** .\[hash\].js

What we now want to do is not load the main file from the `index.html` but within our Chrome extension as a content script.

#### Copy build files to the extension

We could now go ahead and copy & paste all of the three files mentioned above and include them in our `manifest.json` .

But, as the hashes in the filename change after each build, we should automate this. Notice that we could set up Webpack here but let’s keep things simple and just copy all files needed and adjust their filename after each build.

To do that, we create a new script in our `package.json` which will execute those three commands

```sh
cp dist/angular-chrome-app/main*.js ../extension/main.js
cp dist/angular-chrome-app/polyfills*.js ../extension/polyfills.js
cp dist/angular-chrome-app/runtime*.js ../extension/runtime.js
cp dist/angular-chrome-app/styles*.css ../extension/styles.css
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/00da5de9f7d411ae12271c8bad971737)

This will copy all necessary files into our **_/extension_** folder and removes the hashes from the file names. Also, notice that we include our global styles.

Here are our updated scripts in the `package.json` in the **_/angular-chrome-app_** folder:

```json
"scripts": {
  "ng": "ng",
  "start": "ng serve",
  "build": "ng build && yarn copy:build",
  "copy:build": "cp dist/angular-chrome-app/main*.js ../extension/main.js & cp dist/angular-chrome-app/polyfills*.js ../extension/polyfills.js & cp dist/angular-chrome-app/runtime*.js ../extension/runtime.js & cp dist/angular-chrome-app/styles*.css ../extension/styles.css",
  "watch": "ng build --watch --configuration development",
  "test": "ng test"
},
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/884b846d5215aee44fe7f16458bd1f6f)

After each build, we copy the build files to our **_/extension_** folder in which we can now include them by adding them as content scripts like this:

```json
{
  "name": "Angular Chrome Extension",
  "version": "1.0.0",
  "manifest_version": 3,
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["runtime.js", "polyfills.js", "main.js"],
      "css": ["styles.css"]
    }
  ]
}
```

[View this code on GitHub Gist](https://gist.github.com/MariusBongarts/010afe172111d747d96f6045597b696f)

Now, we can go ahead and re-load the extension to apply our changes.

![Screenshot: How to reload extension by clicking reload icon](https://cdn-images-1.medium.com/max/1760/1*wnreH0oI6mC3wbb0zlVGQg.png)

When navigating to any webpage, we should see our Angular application showing up on the left side of the screen:

![Screenshot: Angular App loaded in Chrome Extension](https://cdn-images-1.medium.com/max/1760/1*XtA01UaJ3U2pswjpCYwfBw.png)

*Angular App loaded in Chrome Extension*

Admittedly, this is still not a cool Chrome Extension. But now that we’ve successfully integrated our Angular app into a Chrome extension, you can build any app of your choice with Angular that runs on any webpage.

You can find the code of this article in this [GitHub repository](https://github.com/MariusBongarts/react-chrome-extension) .

### Final Thoughts

Creating your own Chrome Extension is much easier than many may think. Once you set up the extension correctly, you can develop whatever you want using Angular. Being able to design your very own Chrome extension can be a lot of fun as you can let your creativity run wild.

I am always happy to answer questions and am open to criticism. Get in touch with me via [**LinkedIn**](https://www.linkedin.com/in/marius-bongarts-6b3638171/) or [**Twitter**](https://twitter.com/MariusBongarts) **.**
