How to create your own Chrome Extensions with React.
Chrome extensions are a great way to improve a user’s workflow. They reduce context switching and enable the developer’s flow. Here’s how to make them in React.
– Creating a React application
– Making it an extension
– Adding Functionality
– Adding it to Google Chrome Webstore
Creating a React application
The first thing you’ll want to do is create your React application. To streamline this process we’ll use create-react-app
in combination with the Typescript template. In this guide, we’ll create a simple extension for rolling dice. Feel free to create your own, just pay attention to the file names, variable names, and other named parameters.
npx create-react-app roll-dice-extension --template typescript
Making it an extension
Once your app is created, you’ll see a familiar folder structure. Navigate to your public
folder and update config.yaml
. This is a file that specifies the app name, description, icons, and other parameters used by Chrome.
{
"short_name": "Roll Dice",
"name": "A simple extension for rolling dice",
"icons": {
"16": "/logo16.png",
"32": "/logo32.png",
"48": "/logo48.png",
"128": "/logo128.png"
},
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "index.html"
}
}
Before building and uploading your extension to Chrome you’ll have to update the package.json
build script. Replace it with the following.
"build": "set \"INLINE_RUNTIME_CHUNK=false\" && react-scripts build"
This simply removes the unsafe, inline Javascript code from your React application which is not allowed in Chrome Extensions. Now the extension can finally be built by running npm run build
and going to Chrome where you’ll entering chrome://extensions
in the URL bar. This leads you to the extensions page, where the extension can be uploaded. To do this you must first enable developer mode with the toggle in your top right corner and then click on the button that says “Load unpacked” and load your extension by selecting the build
folder in your project.
That’s it. Your extension should now be available for you to run. Go to your extensions, pin it to the Chrome header and try clicking. The following image should appear.
If you want to check out an extension in production, feel free to check out Math Embed — my extension for simple embedding of math equations in Medium. Otherwise, follow along to see how to add basic functionality or go ahead and create your own. (Github for Math Embed)
Adding Functionality
Adding functionality from now on is all a matter of upgrading your React application. We won’t be focusing too much on the details of how it works, since I’m assuming you already have a decent understanding of how React works.
Run npm run start
to start up your development server. You should see the same React app as you saw in the extension, just larger. We need none of that, so simply delete all tsx code in App.tsx
.
//App.tsx
import React from 'react';
import logo from './logo.svg';
import './App.css';function App() {
return (
);
}export default App;
To make our lives a bit easier we’ll install Material UI npm install @material-ui/core
and create a basic theme and layout in our App.tsx
file.
//App.tsx
import {
Box,
Button,
createMuiTheme,
ThemeProvider,
Typography,
} from "@material-ui/core";
import { useState } from "react";
import "./App.css";
import RollDiceButton from "./RollDiceButton";
import RollDisplay from "./RollDisplay";const theme = createMuiTheme({
typography: {
allVariants: {
color: "#FFFFFF",
},
fontFamily: [
"Poppins",
"sans-serif",
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
].join(","),
fontSize: 14,
h1: {
fontSize: 24,
fontWeight: 700,
},
},
});function App() {return (
<ThemeProvider theme={theme}>
<Box
height="100%"
flex={1}
display="flex"
justifyContent="center"
alignItems="center"
flexDirection="column"
bgcolor="#023047"
>
</Box>
</ThemeProvider>
);
}export default App;
With this out of the way, we can take a look at the rest of the functionalities of our app. We’ll be developing:
- A basic display of all throws we made
- A sum of all the throws
- Buttons to increase and decrease the number of dice thrown
- And a button to throw dice.
To achieve these functionalities we’ll develop the following:
- States holding the dice count and separate rolls
- RollDiceButton: A button that takes dice count as the input and returns separate rolls
- RollDisplay: A display of separate rolls and their sum
- Buttons to increase or decrease dice count
We begin by defining two states in App.tsx
— one that stores the separate dice throw values and one that stores the current number of dice we’re throwing.
const [diceRolls, setDiceRolls] = useState<number[]>([]);
const [count, setCount] = useState(2);
Next, we’ll create a new file for the button for rolling dice RollDiceButton.tsx
. The button will take count
as the dice count and setDiceRolls
that will set the state in the parent component.
We will also add simple functions to generate dice rolls getDiceRolls()
and getDiceRolls(count: number)
, which will get triggered on button click.
import { Box, Button } from "@material-ui/core";
import React, { useEffect } from "react";interface RollDiceButtonProps {
count: number;
setDiceRolls: React.Dispatch<React.SetStateAction<number[]>>;
}const getDiceRoll = () => {
return Math.ceil(Math.random() * 6);
};const getDiceRolls = (count: number) => {
var rolls: number[] = [];
for (var i = 0; i < count; i++) {
rolls.push(getDiceRoll());
}
return rolls;
};const RollDiceButton: React.FC<RollDiceButtonProps> = (props) => {
useEffect(() => {
props.setDiceRolls(getDiceRolls(props.count));
}, [props.count]);
return (
<Box>
<Button
variant="contained"
color="primary"
onClick={() => props.setDiceRolls(getDiceRolls(props.count))}
>
Roll Dice
</Button>
</Box>
);
};export default RollDiceButton;
Secondly, we’ll create the display component RollDisplay.tsx
. It will take the separate dice diceRolls
rolls as input and display them in a structured manner including a sum of the rolls.
import { Box, Typography } from "@material-ui/core";
import React from "react";interface RollDisplayProps {
diceRolls: number[];
}const RollDisplay: React.FC<RollDisplayProps> = (props) => {
return (
<Box
display="flex"
justifyContent="center"
alignItems="center"
flexDirection="column"
>
<Box display="flex">
{props.diceRolls.map((roll) => (
<Box padding={1}>
<Typography>{roll}</Typography>
</Box>
))}
</Box>
<Box padding={1}>
<Typography variant="h1">
{props.diceRolls.reduce((acc, value) => acc + value)}
</Typography>
</Box>
</Box>
);
};export default RollDisplay;
Finally, we add them to App.tsx
. We import the required components and include them within the ThemeProvider
.
import {
Box,
Button,
createMuiTheme,
ThemeProvider,
Typography,
} from "@material-ui/core";
import { useState } from "react";
import "./App.css";
import RollDiceButton from "./RollDiceButton";
import RollDisplay from "./RollDisplay";const theme = createMuiTheme({
typography: {
allVariants: {
color: "#FFFFFF",
},
fontFamily: [
"Poppins",
"sans-serif",
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
].join(","),
fontSize: 14,
h1: {
fontSize: 24,
fontWeight: 700,
},
},
});function App() {
const [diceRolls, setDiceRolls] = useState<number[]>([0, 0]);
const [count, setCount] = useState(2);return (
<ThemeProvider theme={theme}>
<Box
height="100%"
flex={1}
display="flex"
justifyContent="center"
alignItems="center"
flexDirection="column"
bgcolor="#006d77"
padding="16px"
>
<Box
display="flex"
justifyContent="center"
alignItems="center"
flexDirection="row"
>
<Button onClick={() => setCount(count > 1 ? count - 1 : 1)}>
<Typography>-</Typography>
</Button>
<RollDisplay diceRolls={diceRolls}></RollDisplay>{" "}
<Button onClick={() => setCount(count + 1)}>
<Typography>+</Typography>
</Button>
</Box><RollDiceButton
setDiceRolls={setDiceRolls}
count={count}
></RollDiceButton>
</Box>
</ThemeProvider>
);
}export default App;
That’s it for the simple extension. If you got lost anywhere, feel free to check out the Github repository for this project. Update it in chrome://extensions
and check it out.
Adding the extension to Google Chrome Webstore
Before publishing, you may want to double check that the extension is working properly. If everything is to order, you are ready to publish it through the Chrome Webstore Developer Console.
Register or Log In the console click on +New Item in the top right corner, which will prompt you for a .zip
file. Simply zip up your project’s build
folder and drop it inside your browser.
Some of the information will be pre-filled from your manifest.json
file. The rest is up to you. After everything is filled out the “Submit for review” button will light up and you’ll be able to submit your extension for review. If it passes, you’ll see it added to the Chrome Web Store.
Congratulations. You made it to the end and your extension should be on the Web Store soon.
Make sure to give me a couple of claps if you found this guide useful and feel free to share it with anyone who might need it.