Have you ever wished to customize your browser experience or add a touch of personalization to your online activities? Well, this project is here to make that wish a reality. We'll walk through the steps of crafting a Chrome extension that not only caters to your preferences but also serves as an excellent introduction to the world of extension development.
In this project, we are aiming to grasp the basic concepts of creating a Chrome Extension. We plan to develop a simple Chrome Extension that allows users to read or listen to Hindi jokes.
A Chrome extension typically consists of several components that work together to provide a specific functionality or enhance the user's browsing experience. Here's a general overview of the structure
of a Chrome extension:
|___Folder Structure of this Chrome Extension project
|
|___Manifest.json
|___Popup.html
|___background.js
|___script.js
|___style.css
|___icon.png
1. Manifest File:
The manifest file, named manifest.json, is a crucial component that defines the extension's metadata and configuration. It includes details such as the extension's name, version, permissions, icons, and pointers to various scripts and resources. Example manifest.json:
manifest.json
{
"manifest_version": 3,
"name": "Hindi Jokes",
"description": "Read/Listen jokes and be Happy!",
"version": "1.0",
"permissions": [
"activeTab",
"scripting",
"storage",
"tts"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
},
"icons": {
"48": "icon.png",
"128": "icon.png"
}
}
All About this file:
manifest_version: this is the version of manifest file , in this project we are working with latest version which is 3.
name: here we will write name of your extension.
description: Description of your extension.
version: this is the version of extension, in our case version is 1.0.
permissions: here we will provide an array of permissions which are required in this project.
background: here we will create a service_worker which will run in background to perform the task even when our extension is inactive or popup is not visible.
action: in action we will provide a default_popup page which will appear when someone will click on the icon of extension.
icons: icon to show in different sizes.
2. Popup Page:
The popup page is a small UI that appears when the user clicks the extension's icon in the Chrome toolbar. It can be a simple HTML page with associated CSS and JavaScript.
Popup.html
<html>
<head>
<link rel="stylesheet" href="/style.css">
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link href="https://cdn.syncfusion.com/ej2/22.1.34/ej2-icons/styles/bootstrap5.css" rel="stylesheet" />
</head>
<body>
<div id="container">
<div id="header">
<div>Hindi Jokes</div>
<div id="reload" class="material-icons" >refresh</div>
<div id="icon" >
<img src="icon.png" >
</div>
</div>
<div id="innerContainer" >
</div>
</div>
</body>
<script src="/script.js"></script>
</html>
In this file, we have html for the popup page.
script.js
document.getElementById("reload").onclick = reload;
async function getjokes() {
if(document.getElementById("errorpage")){
document.getElementById("innerContainer").removeChild(document.getElementById("errorpage"))
}
let child=document.createElement("div");
child.id="loading"
child.innerHTML="loading....."
document.getElementById("innerContainer").appendChild(child);
try {
let response = await fetch(`https://hindi-jokes-api.onrender.com/jokes/10?api_key=${API_KEY}`);
let data = await response.json();
document.getElementById("reload").className="material-icons"
if(document.getElementById("loading")){
document.getElementById("innerContainer").removeChild(document.getElementById("loading"))}
let array=data.data
array.forEach(element => {
let child=document.createElement("div");
let speakercontainer=document.createElement("div")
let speaker=document.createElement("span")
speakercontainer.className="speakercontainer"
speaker.className="e-icons e-medium e-audio speakerclass"
child.className="jock"
child.id=element._id
speakercontainer.id="spk"+element._id
child.innerHTML=element.jokeContent
speakercontainer.appendChild(speaker)
child.appendChild(speakercontainer)
document.getElementById("innerContainer").appendChild(child);
});
var elements = document.getElementsByClassName("speakercontainer");
Array.from(elements).forEach(function(element) {
element.addEventListener("click", function() {
var clickedElementIdspeaker = element.id;
var clickedElementId=clickedElementIdspeaker.substring(3)
var text = document.getElementById(clickedElementId).innerText;
var textToSpeak = text.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '');
chrome.runtime.sendMessage({ action: "speakText", text:textToSpeak });
});
});
} catch (error) {
console.error('Error fetching jokes:', error);
let err=document.createElement("div")
err.id="errorpage"
err.innerText="Something went wrong!"
document.getElementById("innerContainer").appendChild(err)
}
}
getjokes();
async function reload() {
document.getElementById("reload").className="material-icons w3-spin"
var elementsToRemove = document.getElementsByClassName("jock");
var parentContainer = document.getElementById("innerContainer");
while (elementsToRemove.length > 0) {
parentContainer.removeChild(elementsToRemove[0]);
}
getjokes();
}
This file contain all the logics of fetching jokes through API, and creating new elements in popup.html to show these jokes, and send jokes to background.js by clicking on those speaker icons under every joke, through chrome.runtime.sendMessage() api so you can listen the jokes even when popup is inactive or hidden.
style.css
body{
width: 300px;
height: 400px;
display: flex;
flex-direction: column;
}
/* width */
::-webkit-scrollbar {
width: 10px;
}
/* Track */
::-webkit-scrollbar-track {
box-shadow: inset 0 0 5px grey;
border-radius: 10px;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: gray;
border-radius: 10px;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #6c6969;
}
#header{
width: 100%;
height: 30px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
justify-items: center;
font-size: medium;
text-align: center ;
}
#reload{
position: absolute;
right: 15px;
cursor: pointer;
}
#icon{
position: absolute;
left: 15px;
}
img{
height: 25px;
width: 25px;
}
#innerContainer{
padding: 5px;
width: 98%;
display: flex;
overflow-y: auto;
flex-direction: column;
height: calc(100% - 20px);
}
.jock{
margin-bottom:10px;
border: 1px solid gray;
display: flex;
flex-direction: column;
padding: 5px;
border-radius: 5px;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
background-color: rgb(219, 250, 240);
}
#container{
width: 100%;
height: 100%;
}
.speakercontainer{
width: 100%;
display: flex;
justify-content: end;
padding-right: 5px;
}
.speakerclass{
padding: 5px;
border-radius: 10px;
cursor: pointer;
}
.speakerclass:active{
background-color: #9d9d9d;
}
.speakerclass:hover{
background-color: #c9c9c9;
}
#extentionbrowserwindow{
width: 30%;
height: 100%;
display: flex;
position: fixed;
left: 0px;
top: 0px;
background-color: aquamarine;
}
#errorpage{
width: 100%;
height: 100%;
color: black;
display: flex;
align-items: center;
justify-content: center;
}
This file contains all CSS required for popup.html
3. Background Script:
The background script runs in the background and handles events or tasks that require continuous processing, even when the extension's popup or content scripts are not actively running.
Background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.action === "speakText") {
speakLongTextWithTTS(request.text);
}
});
function speakLongTextWithTTS(text) {
var chunkSize = 200;
var chunks = text.match(new RegExp('.{1,' + chunkSize + '}', 'g')) || [];
chrome.tts.getVoices(function(voices) {
function speakChunk(index) {
if (index < chunks.length) {
chrome.tts.speak(chunks[index], {
lang: 'hi-IN',
rate: 1.0,
onEvent: function (event) {
if (event.type === 'end') {
speakChunk(index + 1);
}
}
});
}
}
speakChunk(0);
});
}
In this file, we take jokes from the script.js file by adding a listener chrome.runtime.onMessage.addListener() and speak the jokes by using chrome.tts.speak() api.
Note: it can be possible that chrome.tts.speak() api may not work in some browsers. so try this only in Google Chrome or Microsoft Edge browser.
Now, Let's Try to Load Extension in the browser
Step 1: Open your browser and click on three dots in the top right corner then click on Extensions àManage Extensions

Step 2: on top right corner there will be an Developer mode option, if it Inactive then Activate it.
![]()
Step 3: on left corner there will be an option Load unpacked click on that option and select the folder of the Extension.

Step 4: Now, we can see Extension is loaded in the browser.

Step 5: Click on the Extension icon in top right corner and pin the extension.

Step 6: Now, there will be an icon of your Extension in top right corner click on that icon and you can see your Extension.

Congratulations, You have created your First Extension.
API Key: you can get API KEY from the site
clone full repository from GitHub
If any Queries Please Comment.

