Chrome Extensions 101
Tags: tutorial, javascript, beginners, webdev
Published: 2021-06-27 16:47:16

This blog will discuss how to setup, build and run your own Chrome extension. At the end, you will be able to create a simple **Day Count Down** extension that will display the number of days left to a particular date. 
![Gif image showing the working of the extension](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8sef14kjohtkycvowxck.gif)

Lets go!

###Chrome Extension Terminologies

####manifest.json
   JSON file that tells Chrome what the extension does, what permissions it needs and the files it will use.
####Background script<br/>
A script that runs independent of and parallel to the web page the user is on. It is used for state management and always has only one active instance.
####Content script
   A script that runs in the context of the web page that the user is on. It can access, read and/or modify the DOM of the page that the user visits.


##Setup 

Create a folder for your extension, say Count-Down, and in it a file called `manifest.json`. In the file, add the manifest version, name of the extension, a description and the version of the extension to begin with. The file should now look similar to this.
```json
{
  "manifest_version": 3,
  "name": "Count Down Days",
  "version": "1.0",
  "description": "Takes a date input and displays the number of days left until the given date"
}
```
## Files and Folder structure

Now we go about creating the rest of the elements.
   - A file called _background.js_ in the root folder. This 
     will be our background script.
   - A folder called _content_ in the root folder which will 
     hold: <br/>
    1. a HTML file called _popup.html_. This file will 
          contain the markup for the extension's dropdown menu <br/> 
    2. a JS file called _popup.js_.This is our *content 
          script* <br/>
    3. a CSS file called popup.css to style the elements in our dropdown<br/>
   - A folder for images (extension icon and others - optional)
   
##Link the files to the _manifest.json_

We will be referencing the background script and the HTML file in the _manifest.json_ as follows.

```json
"background": {
    "service_worker": "background.js"
  },
"action": {
    "default_popup": "content/popup.html",
    "default_icon": {
        "16": "images/icon16.png",   // optional
        "24": "images/icon24.png",   // optional
        "32": "images/icon32.png"    // optional
     }
  }
```
The icon is initially set by the _default_icon_ key in the action entry in the manifest.json file. This key takes a dictionary that contains size to image paths. If the icon is not given Chrome automatically assigns an icon. 

The _manifest.json_ should now look like this:

```json
{
  "manifest_version": 3,
  "name": "Count Down Days",
  "version": "0.1",
  "description": "Takes a date input and displays the day count left to the given date ",
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "content/popup.html",
    "default_icon": {
      "16": "/images/timer.png",
      "128": "/images/timer.png",
      "48": "/images/timer.png",
      "256": "/images/timer.png"
  }
  }
}
```
##Running the Extension

Open the Chrome browser and hit the following URL:

``` chrome://extensions ```
In the top right corner you should see a toggle button titled **Developer mode**. 
Check the toggle. 
Now you should see a set of options to load, pack and update extension. 
Select the **Load unpacked** option. 
From the file system, now select the root folder of the extension. 
The extension will have loaded in the browser. 

![An image showing the Chrome extension loaded in the browser](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d3andqsz3kjymygyhxor.png)

## Giving permissions to the Extension
For this extension, we will be using the following permissions:
 
1. _activeTab_ - gives access to the currently active Chrome tab. In our case we need this permission as we are adding to the current active tab. 
2. _scripting_ - allows running scripts in the context of the current web page. We use this permission to inject listener events that perform the date operations.
3. _storage_ - allows the storage of objects in Chrome. We will use this permission to store a date string in Chrome storage.

Add the following line in the _manifest.json_
>"permissions": ["activeTab" ,"storage", "scripting"]

## Adding the logic
Open the background.js and add the following code:

```javascript
let date = "08 15 2021";

chrome.runtime.onInstalled.addListener(() => {

    chrome.storage.sync.set({ date });

    console.log("Default Date set to Aug 15, 2021");

});
```
_chrome.runtime_ is an API that lets the extension retrieve the background page, listen and respond to events.
What we are essentially doing here is using the API to save a default date String in the Chrome storage. This value can be accessed by our content script later. We have also added a log statement which we will use for testing.

In the _popup.html_ we add two buttons (one for displaying number of days left and the other to accept a new Date). We refer our styles - _popup.css_ and content script _popup.js_ in this file as follows.

```html
<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="popup.css" />
  </head>

  <body>
    <div class="buttons">
      <button id="showDays">
        <img class="img-icon" src="../images/timer.png" alt="Sand Clock" />
      </button>
      <button id="changeDate">
        <img class="img-icon" src="../images/change-date.png" alt="Change Date Icon" />
      </button>
    </div>
    <script src="popup.js"></script>
  </body>
</html>
```
I have used image icons for the buttons. Assets are available in the Github link below. Let's add some basic styles in the _popup.css_ as follows. 

```
button {
  height: 30px;
  width: 30px;
  outline: none;
  margin: 10px;
  border: none;
  border-radius: 2px;
}
button img {
  width: 100%;
  height: auto;
}
```

These styles cannot be accessed by the current page. Once this is saved, we go back to the browser, in the _chrome://extensions_ tab we find our extension. Each extension tile will have a refresh icon at the bottom-right corner. 
Refresh the extension and hit the _service worker_ hyperlink to view the logs of our service-worker, i.e., _background.js_.  In this console we will now be able to see our Default date log.

Next step is to view the extension's dropdown. Open out a different tab, in the top-right corner of Chrome the new extension will now be a clickable option. On click of the same, we will be able to see the dropdown menu as follows.

![Image showing dropdown with 2 options](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ltzrhjo4ng2n7d11ae84.png)

> Note: The Chrome extension CANNOT be opened on _chrome://_ URL. 

The buttons will not do anything yet so let's add the listeners that will perform the magic. 

In the _popup.js_ add the following two functions

```javascript
// Content script follows
function showDaysLeft() {
    // get the date string from Chrome storage
    chrome.storage.sync.get("date", ({ date }) => {

        // create a new div that will be appended to the body
        let daysElement = document.createElement("div");
        // adding styles to the new div
        daysElement.style.cssText = "position: absolute; color: black; top: 30px; left: 50%;  transform: translateX(-50%); background-color: pink; z-index: 99999; padding: 1rem; border-radius: 10px; box-shadow: 3px 3px 6px #00000060";
        //  Date.parse converts Date string to milliseconds
        // To get the number of days left we get the difference in milliseconds and divide by 86400000 (milliseconds in a day)
        noOfDaysLeft = parseInt((Date.parse(new Date(date)) - Date.parse(new Date())) / (86400000));
        let content = '';
        if (noOfDaysLeft < 0) {
            content = document.createTextNode("Deadline has already passed.Please set a new one. :D");
            

            alert(daysElement);
        } else {
            content = document.createTextNode(noOfDaysLeft + " days until go time! B)");
            
        }
        // Append the text node to the div
        daysElement.appendChild(content);
        // Append the div to the body tag
        document.body.appendChild(daysElement);
        setTimeout(() => {
            document.body.removeChild(daysElement)
        }, 3000);
    });

}

function resetDate() {
    let newDate = " ";
    let daysElement = document.createElement("div");
    daysElement.style.cssText = "position: absolute; color: black; top: 30px; left: 50%; transform: translateX(-50%); background-color: pink; z-index: 99999; padding: 1rem; border-radius: 10px; box-shadow: 3px 3px 6px #00000060";

    // Get the date string input through window.prompt
    newDate = window.prompt("Enter date in the dd/mm/yyyy format");
    dateArray = newDate.split("/");
    
    dateString = dateArray[1] + " " + dateArray[0] + " " + dateArray[2];
      
    newDate = Date.parse(new Date(dateString));
    let content = '';
    // Check if the format is right 
    if (newDate) {
        noOfDaysLeft = parseInt((Date.parse(new Date(newDate)) - Date.parse(new Date())) / (86400000));
        if (noOfDaysLeft < 0) {
            content = document.createTextNode("Are you time travelling to the past? I am not ready for you yet :D");
            

        } else {
            content = document.createTextNode("New date saved! \n" + noOfDaysLeft + " days until go time! B)");
            
            // save the new date
            chrome.storage.sync.set({ "date": newDate });
        }

    } else {
        content = document.createTextNode("Enter a valid date - date/month/full-year");
        
    }
    daysElement.appendChild(content);
    document.body.appendChild(daysElement);
    setTimeout(() => {
        document.body.removeChild(daysElement)
    }, 3000);


}

```

The function logic is explained in the comments. Now we cannot directly attach the listeners to the buttons. We make use of the _chrome.scripting_ API to inject the listeners into the current page as follows:

```javascript
// Initialize buttons

let showDays = document.getElementById("showDays");
let changeDate = document.getElementById("changeDate");


// When the button is clicked, inject showDaysLeft and resetDate into current page

showDays.addEventListener("click", async () => {

    let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

    chrome.scripting.executeScript({

        target: { tabId: tab.id },

        function: showDaysLeft,

    });

});
changeDate.addEventListener("click", async () => {

    let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

    chrome.scripting.executeScript({

        target: { tabId: tab.id },

        function: resetDate,

    });

});
```
> Note: Apart from the injected listeners other functions/variables cannot be directly run. 

And we are done!😎 Now the extension is ready to be tested. Go back to the browser, refresh the extension and test the extension on a fresh tab. The output should be similar to the gif below.

![Gif image showing the working of the extension](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8sef14kjohtkycvowxck.gif)

Hope this was helpful. The complete project is available on [Github](https://github.com/akshaya-venkatesh8/timer-chrome-ext) Please reach me on [Twitter](twitter.com/venkyakshaya) in case of questions or let me know in the comments below.✌️