search
HomeWeb Front-endJS TutorialChrome Extension Development - Develop minimal app with TypeScript, React, Tailwind CSS and Webpack

Introduction

In this blog, we will explore how to set up and develop a Chrome extension using TypeScript, React, Tailwind CSS, and Webpack. We will create a minimal extension called "NoteMe" ✍️ to put our understanding to the test. Our extension will include the following features:

  • Allow users to add multiple notes for a given website
  • Enable users to view saved notes for a given website
  • Provide the option to delete notes for a given website
  • Save notes locally in the browser’s storage
  • Optionally sync notes with a backend for cloud storage

Refresher

In this blog, we will learn how to build a Chrome extension using modern technologies. This guide assumes that you already have some familiarity with building and uploading an extension to Chrome during local development. If you are new to this or need a detailed walkthrough of the basics, I recommend checking out my previous blog: Link

Extension sneak peek

The extension will include the following components:

  • Toggle Button: A button to open and close the sidebar.
  • Sidebar: A versatile panel where users can: Write new notes. View saved notes. Delete saved notes. Sync notes with the backend (provision available in the code, though no backend is connected currently).
  • Popup: A small window allowing users to reposition the toggle button (used to open/close the sidebar) at prespecified positions on the screen Note: While there’s no backend integration in this implementation, the code includes provisions to connect a backend in the future.

Below are screenshots showcasing how the extension will look upon completion:

Chrome Extension Development - Develop minimal app with TypeScript, React, Tailwind CSS and Webpack

Chrome Extension Development - Develop minimal app with TypeScript, React, Tailwind CSS and Webpack

Prerequisites

Before diving into this tutorial, ensure you have the following tools installed on your system:

  • Node.js (v18.16 LTS or later)
  • NPM (Node Package Manager, bundled with Node.js)
  • TypeScript
  • Webpack
  • VS Code Editor (or any code editor of your choice)

Extension from 40,000 Feet

Chrome Extension Development - Develop minimal app with TypeScript, React, Tailwind CSS and Webpack

The figure above provides a high-level overview of the internal workings of this extension. Here are some key points we can derive from the diagram:

  • The content script interacts directly with the DOM of the parent web page, enabling it to modify the page's content.
  • Popup, background, and content scripts communicate with each other through Chrome's runtime messaging system.
  • For tasks related to Chrome storage or backend API calls, content or popup scripts delegate the responsibility to the background worker using the runtime messaging system.
  • The background script acts as the sole mediator with the app backend and Chrome's storage. It also relays notifications, if any, to other scripts using runtime messaging.
  • Popup and content scripts exchange information directly through Chrome's runtime messaging system.

Setup of the extension

While Chrome extension projects don’t mandate a specific project structure, they do require a manifest.json file to be located at the root of the build directory. Taking advantage of this flexibility, we’ll define a custom project structure that helps organize different scripts effectively. This structure will enable better code reuse across scripts and minimize duplication, streamlining our development process.

Step 1: Create a basic directory structure for the project

To get started, we’ll set up a foundational directory structure for the project. You can use the following bash script to create the basic structure along with the manifest.json file:

#!/bin/bash

bash_script_absolute_path=$(pwd)
declare public_paths=("public" "public/assets" "public/assets/images")
declare source_paths=("src" "src/lib" "src/scripts" "src/scripts/background" "src/scripts/content" "src/scripts/injected" "src/scripts/popup" "src/styles")
declare public_directory_path="public"
declare manifest_file="manifest.json"
declare project_name="note-me"

create_directory () {
    if [ ! -d "" ]; then
        mkdir 
    fi
}

create_file () {
    if [ ! -e "/" ]; then
        touch /
    fi
}

create_public_directories () {
    for public_path in "${public_paths[@]}";
    do
        create_directory $public_path
    done
}

create_source_directories () {
    for source_path in "${source_paths[@]}";
    do
        create_directory $source_path
    done
}

execute () {
    echo "creating project struture at "${bash_script_absolute_path}
    create_directory $project_name
    cd $bash_script_absolute_path"/"$project_name
    create_public_directories
    create_source_directories
    create_file $manifest_file $public_directory_path
    echo "done creating project struture at "${bash_script_absolute_path}" with project name "$project_name
}

execute

Ensure that your directory structure resembles the one shown in the screenshot below.

Chrome Extension Development - Develop minimal app with TypeScript, React, Tailwind CSS and Webpack

Step 2: The manifest.json file located in the public directory should be structured as shown below:

{
    "manifest_version": 3,
    "name": "NoteMe",
    "version": "1.0",
    "description": "A Chrome extension built with React and TypeScript using Webpack.",
    "action": {
      "default_popup": "popup.html",
      "default_icon": "app-icon.png"
    },
    "background": {
      "service_worker": "background.js",
      "type": "module"
    },
    "content_scripts": [
      {
        "matches": ["<all_urls>"],
        "js": ["content.js"],
        "run_at": "document_end"
      }
    ],
    "permissions": [
      "storage",
      "activeTab",
      "scripting",
      "webNavigation"
    ],
    "host_permissions": ["<all_urls>"],
    "web_accessible_resources": [
      {
        "resources": ["styles.css", "sidebar-open.png", "sidebar-close.png"],
        "matches": ["<all_urls>"]
      }
    ]
  }
</all_urls></all_urls></all_urls>

Points to note:

  • The file extensions are .js because the .ts files will be compiled into .js files, which are required at runtime in the Chrome environment.
  • The matches field uses as its value, enabling the extension to operate on any webpage loaded in Chrome.
  • Three image files are referenced: app-icon.png, sidebar-open.png, and sidebar-close.png. You can find these files in the repository linked at the end of this blog.
  • The manifest.json file must be placed at the root level of the dist directory after the project is built. To ensure this, we need to configure the webpack settings to move it appropriately during the build process.

Step 3: Initialize npm and Install Dependencies

  • Start by initializing npm in your project using the following command: npm init -y
  • Add the necessary development dependencies to the devDependencies section of your project. Run the following command: npm i --save-dev @types/chrome @types/react @types/react-dom autoprefixer copy-webpack-plugin css-loader mini-css-extract-plugin postcss postcss-loader style-loader tailwindcss ts-loader typescript webpack webpack-cli webpack-dev-server
  • Add the runtime dependencies needed for running the project: npm i --save react react-dom

Step 4: Create files referenced in the manifest.json

Create following files which are referenced in the manifest.json: backgroun.ts, content.ts and popup.html.

  • background.ts: Create this file in the src/scripts/background directory
  • content.ts: Create this file in the src/scripts/content directory
  • popup.html Create this file in the public directory

Step 5: Update popup and background Code

Add the following code to the popup.html file in the public directory:

#!/bin/bash

bash_script_absolute_path=$(pwd)
declare public_paths=("public" "public/assets" "public/assets/images")
declare source_paths=("src" "src/lib" "src/scripts" "src/scripts/background" "src/scripts/content" "src/scripts/injected" "src/scripts/popup" "src/styles")
declare public_directory_path="public"
declare manifest_file="manifest.json"
declare project_name="note-me"

create_directory () {
    if [ ! -d "" ]; then
        mkdir 
    fi
}

create_file () {
    if [ ! -e "/" ]; then
        touch /
    fi
}

create_public_directories () {
    for public_path in "${public_paths[@]}";
    do
        create_directory $public_path
    done
}

create_source_directories () {
    for source_path in "${source_paths[@]}";
    do
        create_directory $source_path
    done
}

execute () {
    echo "creating project struture at "${bash_script_absolute_path}
    create_directory $project_name
    cd $bash_script_absolute_path"/"$project_name
    create_public_directories
    create_source_directories
    create_file $manifest_file $public_directory_path
    echo "done creating project struture at "${bash_script_absolute_path}" with project name "$project_name
}

execute

Note:

The code above installs two listeners:

  1. The function registered by chrome.runtime.onInstalled.addListener executes whenever the extension is installed in the browser. This can be used to initialize Chrome storage or a backend (if applicable) with a predefined state.
  2. The function registered by chrome.runtime.onMessage.addListener executes whenever the background script receives a message from the content or popup scripts.

Additionally, the import statement brings in listeners from the src/lib directory. The core app logic is built in src/lib, enabling reuse across different contexts (e.g., content and background scripts).

Step 6: Walkthrough of the src/lib Directory

The src/lib directory houses the core logic of the extension. Below is an overview of its structure and key components:

Chrome Extension Development - Develop minimal app with TypeScript, React, Tailwind CSS and Webpack

  • components Directory: Contains all the React components used in the extension.
  • lib/components/ContentApp.tsx: Acts as the container component for the content script.
  • lib/components/NoteMePosition.tsx: Contains the component responsible for the popup script.
  • helpers.ts: Includes helper functions used throughout the extension.
  • storage-model.ts: Manages interactions with Chrome's local storage. For details about the structure of the data stored, refer to this file along with types.ts.
  • types.ts: Defines the custom types used in the extension.
  • worker.ts: Contains callbacks for background event listeners.

For detailed implementation, please refer to the actual code in the repository.

Step 7: Mounting React Components

In this step, we mount the React components for rendering. These components are mounted in two different scripts:src/scripts/content/content.ts and src/scripts/popup/popup.ts.

Popup Script: Found in src/scripts/popup/popup.ts.

#!/bin/bash

bash_script_absolute_path=$(pwd)
declare public_paths=("public" "public/assets" "public/assets/images")
declare source_paths=("src" "src/lib" "src/scripts" "src/scripts/background" "src/scripts/content" "src/scripts/injected" "src/scripts/popup" "src/styles")
declare public_directory_path="public"
declare manifest_file="manifest.json"
declare project_name="note-me"

create_directory () {
    if [ ! -d "" ]; then
        mkdir 
    fi
}

create_file () {
    if [ ! -e "/" ]; then
        touch /
    fi
}

create_public_directories () {
    for public_path in "${public_paths[@]}";
    do
        create_directory $public_path
    done
}

create_source_directories () {
    for source_path in "${source_paths[@]}";
    do
        create_directory $source_path
    done
}

execute () {
    echo "creating project struture at "${bash_script_absolute_path}
    create_directory $project_name
    cd $bash_script_absolute_path"/"$project_name
    create_public_directories
    create_source_directories
    create_file $manifest_file $public_directory_path
    echo "done creating project struture at "${bash_script_absolute_path}" with project name "$project_name
}

execute

Content Script: Found in src/scripts/content/content.ts.

{
    "manifest_version": 3,
    "name": "NoteMe",
    "version": "1.0",
    "description": "A Chrome extension built with React and TypeScript using Webpack.",
    "action": {
      "default_popup": "popup.html",
      "default_icon": "app-icon.png"
    },
    "background": {
      "service_worker": "background.js",
      "type": "module"
    },
    "content_scripts": [
      {
        "matches": ["<all_urls>"],
        "js": ["content.js"],
        "run_at": "document_end"
      }
    ],
    "permissions": [
      "storage",
      "activeTab",
      "scripting",
      "webNavigation"
    ],
    "host_permissions": ["<all_urls>"],
    "web_accessible_resources": [
      {
        "resources": ["styles.css", "sidebar-open.png", "sidebar-close.png"],
        "matches": ["<all_urls>"]
      }
    ]
  }
</all_urls></all_urls></all_urls>
key points:
  • Separate Mounting Scripts:   The popup and content scripts operate in different contexts  
  • Popup Script: Runs within the context of the popup.html webpage in which it is loaded.  
  • Content Script: Runs within the context of the main webpage loaded in the browser.
  • Shadow DOM for Content Script:  
    • Styles injected by the content script could potentially affect the parent webpage's appearance.  
    • To prevent this, we use the Shadow DOM to encapsulate the styles, ensuring they remain isolated within the extension.  
    • This is not necessary for the popup script, as it operates in its own isolated environment (popup.html).

Step 8: Configurations for Compiling and Building

Adding the configurations required for compiling and building the extension

To successfully compile and build the extension, we need to configure the following files:

  1. postcss.config.js
  2. tailwind.config.js
  3. tsconfig.json
  4. webpack.config.js

Key Points:

  • Default Settings:  Wherever possible, default settings are provided to simplify the process and ensure focus remains on the primary goal—building a fully functional extension.
  • Details in Repository: For the complete configurations and detailed settings of these files, please refer to the code repository.

These configurations handle the TypeScript compilation, Tailwind CSS integration, and the overall Webpack build process for the extension.

Testing the extension

  1. Generate the dist Directory: Run the following command to create the dist directory:  npm run build
  2. Upload to Chrome:    
    • Open Chrome and navigate to chrome://extensions/.    
    • Enable Developer Mode in the top-right corner.    
    • Click on Load Unpacked and select the dist directory.
  3. Verify Installation:
    • Once loaded, the extension's icon will appear on each page in the bottom-right corner by default.
  4. Functionality Check:
    • Position Control: Use the controls in the popup to change the position of the icon.
    • Notes Feature: Notes are saved independently for each website and can be deleted for a specific site without affecting others.
  5. Backend Simulation:
    • While there is no backend connected currently, the code includes a provision to integrate with one.
    • The current implementation mimics a backend connection using setTimeout and promises to simulate asynchronous interactions.

Here are some screenshots captured during the testing of the extension.

Chrome Extension Development - Develop minimal app with TypeScript, React, Tailwind CSS and Webpack

Chrome Extension Development - Develop minimal app with TypeScript, React, Tailwind CSS and Webpack

Chrome Extension Development - Develop minimal app with TypeScript, React, Tailwind CSS and Webpack

Key Takeaways

Here are a few key takeaways from this blog,

  • We explored how various components of the Chrome environment, such as content scripts, popup scripts, and background workers, communicate with each other using Chrome's runtime messaging system.
  • We learned how to configure and build a Chrome extension from scratch, including setting up the project structure, installing dependencies, and writing core functionality.
  • We discovered some good practices, such as:
    • Enhancing code reusability across scripts for maintainability and scalability.
    • Utilizing Shadow DOM in content scripts to prevent style conflicts with the parent webpage.

Glimpse Ahead

In the future, I plan to work on another blog where we will explore the process of publishing a fully functional Chrome extension to the Chrome Web Store. The goal of that blog will be to:

  • Develop an extension complex enough to solve a real-world problem.
  • Demonstrate the step-by-step process of publishing the extension to the Chrome Web Store.

Thank you for taking the time to read this blog! Your interest and support mean so much to me. I’m excited to share more insights as I continue this journey.

Happy coding!

github link: https://github.com/gauravnadkarni/chrome-extension-starter-app

This article was originally published on Medium.

The above is the detailed content of Chrome Extension Development - Develop minimal app with TypeScript, React, Tailwind CSS and Webpack. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Understanding the JavaScript Engine: Implementation DetailsUnderstanding the JavaScript Engine: Implementation DetailsApr 17, 2025 am 12:05 AM

Understanding how JavaScript engine works internally is important to developers because it helps write more efficient code and understand performance bottlenecks and optimization strategies. 1) The engine's workflow includes three stages: parsing, compiling and execution; 2) During the execution process, the engine will perform dynamic optimization, such as inline cache and hidden classes; 3) Best practices include avoiding global variables, optimizing loops, using const and lets, and avoiding excessive use of closures.

Python vs. JavaScript: The Learning Curve and Ease of UsePython vs. JavaScript: The Learning Curve and Ease of UseApr 16, 2025 am 12:12 AM

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

Python vs. JavaScript: Community, Libraries, and ResourcesPython vs. JavaScript: Community, Libraries, and ResourcesApr 15, 2025 am 12:16 AM

Python and JavaScript have their own advantages and disadvantages in terms of community, libraries and resources. 1) The Python community is friendly and suitable for beginners, but the front-end development resources are not as rich as JavaScript. 2) Python is powerful in data science and machine learning libraries, while JavaScript is better in front-end development libraries and frameworks. 3) Both have rich learning resources, but Python is suitable for starting with official documents, while JavaScript is better with MDNWebDocs. The choice should be based on project needs and personal interests.

From C/C   to JavaScript: How It All WorksFrom C/C to JavaScript: How It All WorksApr 14, 2025 am 12:05 AM

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

JavaScript Engines: Comparing ImplementationsJavaScript Engines: Comparing ImplementationsApr 13, 2025 am 12:05 AM

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

Beyond the Browser: JavaScript in the Real WorldBeyond the Browser: JavaScript in the Real WorldApr 12, 2025 am 12:06 AM

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.

Building a Multi-Tenant SaaS Application with Next.js (Backend Integration)Building a Multi-Tenant SaaS Application with Next.js (Backend Integration)Apr 11, 2025 am 08:23 AM

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration)How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration)Apr 11, 2025 am 08:22 AM

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat Commands and How to Use Them
1 months agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)