How to Change a Webpage UI with a Chrome Extension
Tags: webdev, javascript, react, opensource
Published: 2023-07-26 13:54:46

Have you ever wondered how chrome extensions can change the UI of some of your favorite websites, like YouTube and GitHub? Chrome extensions can be a powerful tool for boosting productivity, helping you to debug code, and sometimes just plain fun. Hopefully, by the end of this blog post, you'll have an idea of how the magic happens, and how you can use content scripts to create your own UI magic through a chrome extension. I'll walk you through the process of how we do it using the [OpenSauced.ai](https://opensauced.ai/) chrome extension. If you want to do a deep dive into the extension, there's a link to the repository at the end of this post. 

The OpenSauced.ai chrome extension is a versatile tool that helps both open source maintainers and contributors increase their productivity. It uses AI tools and integrates smoothly with the OpenSauced platform to enhance discoverability.

This extension modifies the GitHub web page and adds helpful elements with features to facilitate code reviews, enable direct interaction with OpenSauced on GitHub, and provide additional functionalities such as generating tests and explaining code.

![One such injected element in action](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c8z87vyocmhtbd1prusq.gif)

But how does that work exactly? How can a chrome extension insert UI elements into a webpage? 🤔

## DOMination: Unleashing the Power of Content Scripts

This is where [content scripts](https://developer.chrome.com/docs/extensions/mv3/content_scripts/) play a crucial role. Content scripts are a feature provided by Chrome extensions that allow them to manipulate and modify the DOM (Document Object Model) of a webpage. They act as a bridge between the extension and the webpage, enabling the injection of UI elements seamlessly. By utilizing content scripts, the OpenSauced.ai chrome extension is able to add its useful features and enhance the user experience on GitHub.

## Creating a content script for a Chrome Extension

You can create your content script, a standard JavaScript/TypeScript file in the src/ folder for you chrome extension, we later discuss how you register it in manifest.json in the root.

Content scripts can read details of the web pages the browser visits, make changes to them, and pass information to their parent extension. Therefore, we can read the current URL and perform various actions based on the page the user is on!

In the OpenSauced.ai chrome extension, we use this information to decide which element needs to be injected into the page. The "View on OpenSauced" button, for example, should be injected if the current page is a profile page, and the various PR review features should only be injected when the current page is a code review page.

All your conditionals and injections should go inside this content-script. Here's an example snippet from the OpenSauced.ai chrome extension:

```ts
if (isGithubProfilePage(window.location.href)) {
        const username = getGithubUsername(window.location.href);

        if (!username) {
            return;
        }
        if (await isOpenSaucedUser(username)) {
            injectViewOnOpenSauced(username);
        }
}
```
This code checks if the current page is a GitHub profile page, like [github.com/diivi](https://github.com/diivi), and renders the "View on OpenSauced" button if the user exists on OpenSauced too, easy!

## Injecting a custom UI component into the webpage💉
Injecting components into the DOM is as simple as creating a [Node](https://www.w3schools.com/js/js_htmldom_nodes.asp) through JavaScript's `createElement` function, and adding it to the DOM by using any method that you like-we use the `appendChild` method-but there's also `insertBefore` and other similar methods. Here's a usage example from the OpenSauced.ai chrome extension:

```js
const injectViewOnOpenSaucedButton = (username: string) => {
    if (document.getElementById("view-on-opensauced-button")) {
        return;
    }
```
This section handles duplicate nodes: we add an id to the node and if a node already exists with that id in the DOM (due to rerenders or other technical issues), we don't append the Node to the DOM again.

```js
    const viewOnOpenSaucedButton = ViewOnOpenSaucedButton(username);
```
The ViewOnOpenSaucedButton is a component (Node) that has all HTML, CSS and JS for the "View on OpenSauced Button". We have separated the view from the logic here.

```js
    const userBio = document.querySelector(
        `${GITHUB_PROFILE_USER_PROFILE_BIO_SELECTOR}, ${GITHUB_PROFILE_EDIT_MENU_SELECTOR}`,
    );

    userBio?.append(viewOnOpenSaucedButton);
};
```
Since we have access to the webpage's DOM, we can find the component we want to inject our Node into, and use the `append` method to actually inject it.

## Registering the Script 📜 

Content scripts are registered in the `manifest.json` file under the "content_scripts" field, like so:

```json
{
 "name": "OpenSauced.ai",
 ...
 "content_scripts": [
   {
      "js": ["src/content-scripts/github.ts"],
      "matches": ["https://github.com/*"],
       ...
   }
 ],
 ...
}
```

This is a snippet from the OpenSauced.ai chrome extension's `manifest.json` file. Here, the `js` key expects an array of the paths where the content scripts to be executed reside, and the `matches` key expects an array of URLs of the webpages which this content script will be injected into.

Now we run the extension, and voila! 🎉

![View on OpenSauced Button result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/01o0k6ikmi91amc7vleb.png)

The button is successfully injected right where I wanted it! 

There are a lot of different possibilities for what you can do if you create your own chrome extension. You can find the full code for our chrome extension in our [open-sauced/ai repo](https://github.com/open-sauced/ai). As you've seen from the gif at the top of this blog post, our extension has features for refactoring code, writing tests, and explaining code. You can also interact with [OpenSauced highlights](https://insights.opensauced.pizza/feed) and more. But there are so many different options for what chrome extensions can do, like adding gifs to your PRs or for interacting with posts online. What have been the most interesting features you've seen in a chrome extension.