How to Use React.js to Create a Chrome Extension?

Hire Reactjs Developers

In this post, we will guide you seamlessly through the process of using React.js to create the Chrome extension. By the end of this guide, you will be able to build your own extension functionality.

So, without further ado,  let’s get started. 

What are the Extensions? 

Small software programs that personalize the browsing experience, giving users the freedom to tailor the behavior and Chrome functionality keeping in mind the needs of the individual. Extensions are developed on different web technologies, including CSS, JS, and HTML. The purpose of having an extension is to make everything easy to understand. There are multiple components with different ranges of functionality in a single extension. 

How to Create React App? 

Reactjs Developers

In this step, we will be starting from a TypeScript React project created with the create-react-app CLI command. 

npx create-react-app my-app –template typescript

Update the Manifest.json File 

Now, if we are trying to create our extension work seamlessly, without any interruption, we will have to update the manifest.json file in the /public folder. 

{

  “name”: “Hello Extensions”,

  “description”: “Base Level Extension”,

  “version”: “1.0”,

  “manifest_version”: 2,

  “browser_action”: {

    “default_popup”: “index.html”,

    “default_title”: “Open the popup”

  },

  “icons”: {

    “16”: “logo192.png”,

    “48”: “logo192.png”,

    “128”: “logo192.png”

  }

}

Default_popup will help us know how to find out the main HTML file. 

Default_title helps us know what text the user will be shown when they hover on the extension icon. 

Create React App, by default, embeds the small runtime script into index.html during the production build. Further, it minimizes the number of HTTP requests. There is a high possibility that you are going to witness console errors related to CSP. Besides, you can even turn off the embedding behavior. For that, all you need to do is set the inline_runtime_chunk flag to false. Also, you can add inline_runtime_chunk to your .env file or even add it before the build script. 

INLINE_RUNTIME_CHUNK=false

Alternatively, you can try adding content_security_policy to the manifest.json file. 

“content_security_policy”: “script-src ‘self’ ‘unsafe-eval’; object-src ‘self'”

Once the manifest.json file is updated, it is time to run the yarn run build script. And, once that is finished, a new build folder is created at the root of the project. 

After that, we just need to inform Chrome how and where to find the new extension. For that, we need to type in the Chrome Tab the following for opening the extension menu:

chrome://extensions/

Now, we will be selecting the /build folder of the project.

(Once you have updated/saved the code, click on Update to update all the extensions used.)

Check out the difference between Reactjs, angularjs and vuejs.

What do you need to know about Popup Width and Height Restrictions? 

Reactjs Apps

We have created the extension until this step, but it might not look as good as we want. Hence, we will have to set the height and width of the CSS properties in the index.css file. And then save, rebuild, and update. 

For the width and height of the extensions, you need to make them 800px and 600px, respectively. 

How to Retrieve the Active Tab’s URL? 

For this, we will have to add permissions to the manifest.json file. 

“permissions”: [

“activeTab”

]

After that is done, we will add useEffect hook to the App.tsx file. 

import React, { useEffect, useState } from ‘react’;

import logo from ‘./logo.svg’;

import ‘./App.css’;

export const App = () => {

    const [url, setUrl] = useState<string>(”);

    /**

     * Get current URL

     */

    useEffect(() => {

        const queryInfo = {active: true, lastFocusedWindow: true};

        chrome.tabs && chrome.tabs.query(queryInfo, tabs => {

            const url = tabs[0].url;

            setUrl(url);

        });

    }, []);

    return (

        <div className=”App”>

            <header className=”App-header”>

                <img src={logo} className=”App-logo” alt=”logo”/>

                <p>URL:</p>

                <p>

                    {url}

                </p>

            </header>

        </div>

    );

};

Now, you can save, rebuild, and update the extension to achieve the final look we want. 

DOM Content Manipulation (Content Scripts)

So, we need to use the Content Scripts to access the DOM of the page. So, what are the content scripts? Well, these are the files that run in the context of web pages. When the DOM is used, it helps read every detail about the web pages the browser visits. Besides, it can even make changes to them and even pass essential information to the parent extension. 

However, we will not be able to access the content.js file directly. We need to use Message Passing for that. 

  • Add content.js file to manifest.json file
  • Add optional_permissions to manifest.json file 

“optional_permissions”: [

 “<all_urls>”

]

Adding Content Script File to the Project 

Reactjs Apps

Now is the time to place the content script in the /public folder directly. However, we can’t really do that because we don’t have all the TypeScript features that we need. 

So, for that, we need to place the content script to the /src/chrome/content.js

import { ChromeMessage, Sender } from “../types”;

const messagesFromReactAppListener = (message: ChromeMessage, sender, response) => {

    console.log(‘[content.js]. Message received’, {

        message,

        sender,

    })

    if (

        sender.id === chrome.runtime.id &&

        message.from === Sender.React &&

        message.message === ‘Hello from React’) {

        response(‘Hello from content.js’);

    }

    if (

        sender.id === chrome.runtime.id &&

        message.from === Sender.React &&

        message.message === “delete logo”) {

        const logo = document.getElementById(‘hplogo’);

        logo.parentElement.removeChild(logo)

    }

}

/**

 * Fired when a message is sent from either an extension process or a content script.

 */

chrome.runtime.onMessage.addListener(messagesFromReactAppListener);

Now, we will update the manifest.json file and, after that App.tsx file. So, when the user clicks on the button, they are redirected to the content script. 

import React, { useEffect, useState } from ‘react’;

import logo from ‘./logo.svg’;

import { ChromeMessage, Sender } from “./types”;

import ‘./App.css’;

export const App = () => {

    const [url, setUrl] = useState<string>(”);

    const [responseFromContent, setResponseFromContent] = useState<string>(”);

    /**

     * Get current URL

     */

    useEffect(() => {

        const queryInfo = {active: true, lastFocusedWindow: true};

        chrome.tabs && chrome.tabs.query(queryInfo, tabs => {

            const url = tabs[0].url;

            setUrl(url);

        });

    }, []);

    /**

     * Send message to the content script

     */

    const sendTestMessage = () => {

        const message: ChromeMessage = {

            from: Sender.React,

            message: “Hello from React”,

        }

        const queryInfo: chrome.tabs.QueryInfo = {

            active: true,

            currentWindow: true

        };

        /**

         * We can’t use “chrome.runtime.sendMessage” for sending messages from React.

         * For sending messages from React we need to specify which tab to send it to.

         */

        chrome.tabs && chrome.tabs.query(queryInfo, tabs => {

            const currentTabId = tabs[0].id;

            /**

             * Sends a single message to the content script(s) in the specified tab,

             * with an optional callback to run when a response is sent back.

             *

             * The runtime.onMessage event is fired in each content script running

             * in the specified tab for the current extension.

             */

            chrome.tabs.sendMessage(

                currentTabId,

                message,

                (response) => {

                    setResponseFromContent(response);

                });

        });

    };

    const sendRemoveMessage = () => {

        const message: ChromeMessage = {

            from: Sender.React,

            message: “delete logo”,

        }

        const queryInfo: chrome.tabs.QueryInfo = {

            active: true,

            currentWindow: true

        };

        chrome.tabs && chrome.tabs.query(queryInfo, tabs => {

            const currentTabId = tabs[0].id;

            chrome.tabs.sendMessage(

                currentTabId,

                message,

                (response) => {

                    setResponseFromContent(response);

                });

        });

    };

    return (

        <div className=”App”>

            <header className=”App-header”>

                <img src={logo} className=”App-logo” alt=”logo”/>

                <p>URL:</p>

                <p>

                    {url}

                </p>

                <button onClick={sendTestMessage}>SEND MESSAGE</button>

                <button onClick={sendRemoveMessage}>Remove logo</button>

                <p>Response from content:</p>

                <p>

                    {responseFromContent}

                </p>

            </header>

        </div>

    );

};

With the Webpack, we can bundle all the React app scripts into one bundle. We will convert the content.ts file to content.js before placing it in static/js/content.js and pointing it to the manifest.json file. 

 “content_scripts”: [

    {

      “matches”: [“http://*/*”, “https://*/*”],

      “js”: [“./static/js/content.js”],

      “all_frames”: false,

      “run_at”: “document_end”

    }

  ],

Now, We Will Override Create React App Configuration
Hire React Developers

It is time now to override Create React App configuration, for which we need to use craco npm package. 

yarn add @craco/craco

Now, we need to add the craco.config.js configuration file to the project’s root. 

module.exports = {

    webpack: {

        configure: (webpackConfig, {env, paths}) => {

            return {

                …webpackConfig,

                entry: {

                    main: [env === ‘development’ &&

                    require.resolve(‘react-dev-utils/webpackHotDevClient’),paths.appIndexJs].filter(Boolean),

                    content: ‘./src/chrome/content.ts’,

                },

                output: {

                    …webpackConfig.output,

                    filename: ‘static/js/[name].js’,

                },

                optimization: {

                    …webpackConfig.optimization,

                    runtimeChunk: false,

                }

            }

        },

    }

}

We will be updating the build script now. 

“scripts”: {

    “start”: “react-scripts start”,

    “build”: “INLINE_RUNTIME_CHUNK=false craco build”,

    “test”: “react-scripts test”,

    “eject”: “react-scripts eject”

  },

After that, we need to run a yarn run build script. 

Great, this is the step to add the content script to our manifest.json file. 

{

  “name”: “Hello Extensions”,

  “description” : “Base Level Extension”,

  “version”: “1.0”,

  “manifest_version”: 2,

  “browser_action”: {

    “default_popup”: “index.html”,

    “default_title”: “Open the popup”

  },

  “icons”: {

    “16”: “logo192.png”,

    “48”: “logo192.png”,

    “128”: “logo192.png”

  },

  “content_scripts”: [

    {

      “matches”: [“http://*/*”, “https://*/*”],

      “js”: [“./static/js/content.js”],

      “all_frames”: false,

      “run_at”: “document_end”

    }

  ],

  “permissions”: [

    “activeTab”

  ],

  “optional_permissions”: [

    “<all_urls>”

  ]

}

Now, just save, rebuild, and update the extension. 

Finally, you can disable all the chrome extensions you have installed and restart the browser to ensure everything works fine. 

Conclusion

Congratulations! You have successfully learned how to use React.js to create a Chrome extension. However, don’t forget to disable all Chrome extensions when you are done with all the steps to ensure your newly created extension works fine. 

Need help setting up a dedicated team of Reactjs developers in India? At Your Team In India, we have a pool of certified Reactjs engineers. Connect with us our business head now and get a free consultation.

Subscribe to get regular content updates, and offers

Also Read This

Best Offshore Development Team

Cost-Benefit Analysis of Outsourcing

Offshore Development Centre

Offshore Development Center in India

ODC Centre

HOW IT WORKS?