├── src
├── vite-env.d.ts
├── background.ts
├── main.tsx
├── App.css
├── App.tsx
├── index.css
└── assets
│ └── react.svg
├── tsconfig.json
├── public
├── manifest.json
└── vite.svg
├── .gitignore
├── tsconfig.node.json
├── index.html
├── .eslintrc.cjs
├── tsconfig.app.json
├── vite.config.ts
├── package.json
└── README.md
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "references": [
4 | {
5 | "path": "./tsconfig.app.json"
6 | },
7 | {
8 | "path": "./tsconfig.node.json"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/src/background.ts:
--------------------------------------------------------------------------------
1 | chrome.runtime.onInstalled.addListener(() => {
2 | console.log('Chrome extension installed');
3 | });
4 |
5 | chrome.action.onClicked.addListener((tab) => {
6 | console.log('Extension icon clicked', tab);
7 | });
--------------------------------------------------------------------------------
/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.tsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')!).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 3,
3 | "name": "React Chrome Extension",
4 | "version": "1.0.0",
5 | "description": "A simple React app as a Chrome extension",
6 | "action": {
7 | "default_popup": "index.html"
8 | },
9 | "background": {
10 | "service_worker": "background.js"
11 | },
12 | "permissions": []
13 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | build
16 |
17 | # Editor directories and files
18 | .vscode/*
19 | !.vscode/extensions.json
20 | .idea
21 | .DS_Store
22 | *.suo
23 | *.ntvs*
24 | *.njsproj
25 | *.sln
26 | *.sw?
27 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
5 | "skipLibCheck": true,
6 | "module": "ESNext",
7 | "moduleResolution": "bundler",
8 | "allowSyntheticDefaultImports": true,
9 | "strict": true,
10 | "noEmit": true
11 | },
12 | "include": ["vite.config.ts"]
13 | }
14 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | React Chrome Extension
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:@typescript-eslint/recommended',
7 | 'plugin:react-hooks/recommended',
8 | ],
9 | ignorePatterns: ['dist', '.eslintrc.cjs'],
10 | parser: '@typescript-eslint/parser',
11 | plugins: ['react-refresh'],
12 | rules: {
13 | 'react-refresh/only-export-components': [
14 | 'warn',
15 | { allowConstantExport: true },
16 | ],
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
5 | "target": "ES2020",
6 | "useDefineForClassFields": true,
7 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
8 | "module": "ESNext",
9 | "skipLibCheck": true,
10 |
11 | /* Bundler mode */
12 | "moduleResolution": "bundler",
13 | "allowImportingTsExtensions": true,
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "moduleDetection": "force",
17 | "noEmit": true,
18 | "jsx": "react-jsx",
19 |
20 | /* Linting */
21 | "strict": true,
22 | "noUnusedLocals": true,
23 | "noUnusedParameters": true,
24 | "noFallthroughCasesInSwitch": true
25 | },
26 | "include": ["src"]
27 | }
28 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 | import { viteStaticCopy } from 'vite-plugin-static-copy';
4 |
5 | export default defineConfig({
6 | plugins: [
7 | react(),
8 | viteStaticCopy({
9 | targets: [
10 | {
11 | src: 'public/manifest.json',
12 | dest: '.',
13 | }
14 | ],
15 | }),
16 | ],
17 | build: {
18 | outDir: 'build',
19 | rollupOptions: {
20 | input: {
21 | main: './index.html',
22 | background: './src/background.ts',
23 | },
24 | output: {
25 | entryFileNames: (chunkInfo) => {
26 | return chunkInfo.name === 'background' ? 'background.js' : 'assets/[name]-[hash].js';
27 | },
28 | },
29 | },
30 | },
31 | });
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chrome-extension-react-template",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc -b && vite build",
9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "react": "^19.1.1",
14 | "react-dom": "^19.1.1"
15 | },
16 | "devDependencies": {
17 | "@types/chrome": "^0.1.4",
18 | "@types/react": "^19.1.12",
19 | "@types/react-dom": "^19.1.9",
20 | "@typescript-eslint/eslint-plugin": "^8.0.0",
21 | "@typescript-eslint/parser": "^8.0.0",
22 | "@vitejs/plugin-react": "^5.0.0",
23 | "eslint": "^9.0.0",
24 | "eslint-plugin-react-hooks": "^5.0.0",
25 | "eslint-plugin-react-refresh": "^0.4.14",
26 | "typescript": "^5.6.0",
27 | "vite": "^6.3.5",
28 | "vite-plugin-static-copy": "^3.1.2"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import reactLogo from './assets/react.svg'
3 | import viteLogo from '/vite.svg'
4 | import './App.css'
5 |
6 | function App() {
7 | const [count, setCount] = useState(0)
8 |
9 | return (
10 | <>
11 |
19 | Vite + React
20 |
21 |
24 |
25 | Edit src/App.tsx and save to test HMR
26 |
27 |
28 |
29 | Click on the Vite and React logos to learn more
30 |
31 | >
32 | )
33 | }
34 |
35 | export default App
36 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3 | line-height: 1.5;
4 | font-weight: 400;
5 |
6 | color-scheme: light dark;
7 | color: rgba(255, 255, 255, 0.87);
8 | background-color: #242424;
9 |
10 | font-synthesis: none;
11 | text-rendering: optimizeLegibility;
12 | -webkit-font-smoothing: antialiased;
13 | -moz-osx-font-smoothing: grayscale;
14 | }
15 |
16 | a {
17 | font-weight: 500;
18 | color: #646cff;
19 | text-decoration: inherit;
20 | }
21 | a:hover {
22 | color: #535bf2;
23 | }
24 |
25 | body {
26 | margin: 0;
27 | display: flex;
28 | place-items: center;
29 | min-width: 320px;
30 | min-height: 100vh;
31 | }
32 |
33 | h1 {
34 | font-size: 3.2em;
35 | line-height: 1.1;
36 | }
37 |
38 | button {
39 | border-radius: 8px;
40 | border: 1px solid transparent;
41 | padding: 0.6em 1.2em;
42 | font-size: 1em;
43 | font-weight: 500;
44 | font-family: inherit;
45 | background-color: #1a1a1a;
46 | cursor: pointer;
47 | transition: border-color 0.25s;
48 | }
49 | button:hover {
50 | border-color: #646cff;
51 | }
52 | button:focus,
53 | button:focus-visible {
54 | outline: 4px auto -webkit-focus-ring-color;
55 | }
56 |
57 | @media (prefers-color-scheme: light) {
58 | :root {
59 | color: #213547;
60 | background-color: #ffffff;
61 | }
62 | a:hover {
63 | color: #747bff;
64 | }
65 | button {
66 | background-color: #f9f9f9;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Chrome Extension Template
2 |
3 | This is a template for creating a Chrome extension using React and [Vite](https://vitejs.dev/) with TypeScript.
4 |
5 |
6 | ## Getting Started
7 |
8 | ### Prerequisites
9 |
10 | Make sure you have [Node.js](https://nodejs.org/) (version 18+ or 20+) installed on your machine.
11 |
12 | ### Setup
13 |
14 | 1. Clone or fork the repository :
15 |
16 | ```sh
17 | # To clone
18 | git clone https://github.com/5tigerjelly/chrome-extension-react-template
19 | cd chrome-extension-react-template
20 | ```
21 |
22 | 2. Install the dependencies:
23 |
24 | ```sh
25 | npm install
26 | ```
27 |
28 | ## 🏗️ Development
29 |
30 | To start the development server:
31 |
32 | ```sh
33 | npm run dev
34 | ```
35 |
36 | This will start the Vite development server and open your default browser.
37 |
38 | ## 📦 Build
39 |
40 | To create a production build:
41 |
42 | ```sh
43 | npm run build
44 | ```
45 |
46 | This will generate the build files in the `build` directory.
47 |
48 | ## 📂 Load Extension in Chrome
49 |
50 | 1. Open Chrome and navigate to `chrome://extensions/`.
51 | 2. Enable "Developer mode" using the toggle switch in the top right corner.
52 | 3. Click "Load unpacked" and select the `build` directory.
53 |
54 | Your React app should now be loaded as a Chrome extension!
55 |
56 | ## 🗂️ Project Structure
57 |
58 | - `public/`: Contains static files and the `manifest.json`.
59 | - `src/`: Contains the React app source code.
60 | - `vite.config.ts`: Vite configuration file.
61 | - `tsconfig.json`: TypeScript configuration file.
62 | - `package.json`: Contains the project dependencies and scripts.
63 |
64 | ## License
65 |
66 | This project is licensed under the MIT License.
--------------------------------------------------------------------------------
/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------