Have you ever wanted to spam yourself with annoying and invasive notifications? Or remind yourself that our work plan for today is coming whenever the web?
Wow, not far away.
The Chrome Extension can do all of this, and the best part is that you can’t exit the app by reloading the page. Plus, not everyone knows how to turn off these annoying things.
In this article, we will try to create a Todo application and deploy it under Local as a Chrome extension with React. Actually this is not necessary, but try crazy a little it awakens creativity a bit.
Prerequisites:
- Introductory knowledge about React
- A little familiarity with custom React Hooks
Clone the Repo:
Clone: https://gitlab.com/sk3pt1cc/react-starter
Run cmd npm install
& npm run start
Open localhost:3000
to try and run the application.
Create Todo App
There are 3 parts: App Component, Component form to create Todos, and useTodos
Hook. We will go into each part in detail
<CreateTodoForm />
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">CreateTodoForm</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> createNewTodo <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> label <span class="token punctuation">,</span> setLabel <span class="token punctuation">]</span> <span class="token operator">=</span> React <span class="token punctuation">.</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token string">''</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span> div className <span class="token operator">=</span> <span class="token string">"create-todo-form"</span> <span class="token operator">></span> <span class="token operator"><</span> input placeholder <span class="token operator">=</span> <span class="token string">"Enter todo label"</span> onChange <span class="token operator">=</span> <span class="token punctuation">{</span> e <span class="token operator">=></span> <span class="token function">setLabel</span> <span class="token punctuation">(</span> e <span class="token punctuation">.</span> target <span class="token punctuation">.</span> value <span class="token punctuation">)</span> <span class="token punctuation">}</span> value <span class="token operator">=</span> <span class="token punctuation">{</span> label <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> button onClick <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">createNewTodo</span> <span class="token punctuation">(</span> label <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator">></span> Save <span class="token operator"><</span> <span class="token operator">/</span> button <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> CreateTodoForm <span class="token punctuation">;</span> |
A simple form to enter the Label and a button to save information. When it receives a function createNewTodo
prop.
useTodos
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token punctuation">;</span> <span class="token keyword">import</span> uuid <span class="token keyword">from</span> <span class="token string">"uuid"</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">getTodos</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> todos <span class="token operator">=</span> window <span class="token punctuation">.</span> localStorage <span class="token punctuation">.</span> <span class="token function">getItem</span> <span class="token punctuation">(</span> <span class="token string">'todos'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> todos <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token constant">JSON</span> <span class="token punctuation">.</span> <span class="token function">parse</span> <span class="token punctuation">(</span> todos <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">const</span> <span class="token function-variable function">useTodos</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> todos <span class="token punctuation">,</span> setTodos <span class="token punctuation">]</span> <span class="token operator">=</span> React <span class="token punctuation">.</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token function">getTodos</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">updateTodos</span> <span class="token operator">=</span> <span class="token punctuation">(</span> newTodos <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> stringifiedTodos <span class="token operator">=</span> <span class="token constant">JSON</span> <span class="token punctuation">.</span> <span class="token function">stringify</span> <span class="token punctuation">(</span> newTodos <span class="token punctuation">)</span> <span class="token punctuation">;</span> window <span class="token punctuation">.</span> localStorage <span class="token punctuation">.</span> <span class="token function">setItem</span> <span class="token punctuation">(</span> <span class="token string">'todos'</span> <span class="token punctuation">,</span> stringifiedTodos <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setTodos</span> <span class="token punctuation">(</span> newTodos <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">setTodoCompleted</span> <span class="token operator">=</span> <span class="token punctuation">(</span> id <span class="token punctuation">,</span> completed <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> todoIds <span class="token operator">=</span> todos <span class="token punctuation">.</span> <span class="token function">findIndex</span> <span class="token punctuation">(</span> todo <span class="token operator">=></span> todo <span class="token punctuation">.</span> id <span class="token operator">==</span> id <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> newTodos <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token operator">...</span> todos <span class="token punctuation">]</span> <span class="token punctuation">;</span> newTodos <span class="token punctuation">[</span> todoIds <span class="token punctuation">]</span> <span class="token punctuation">.</span> completed <span class="token operator">=</span> completed <span class="token punctuation">;</span> <span class="token function">updateTodos</span> <span class="token punctuation">(</span> newTodos <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">addTodo</span> <span class="token operator">=</span> <span class="token punctuation">(</span> label <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> newTodos <span class="token operator">=</span> <span class="token punctuation">{</span> label <span class="token punctuation">,</span> completed <span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> id <span class="token punctuation">:</span> <span class="token function">uuid</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token function">updateTodos</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token operator">...</span> todos <span class="token punctuation">,</span> newTodos <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> todos <span class="token punctuation">,</span> addTodo <span class="token punctuation">,</span> setTodoCompleted <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> useTodos <span class="token punctuation">;</span> |
This is the most important part so we will analyze it little by little.
1 2 3 4 5 6 7 8 | <span class="token keyword">const</span> <span class="token function-variable function">getTodos</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> todos <span class="token operator">=</span> window <span class="token punctuation">.</span> localStorage <span class="token punctuation">.</span> <span class="token function">getItem</span> <span class="token punctuation">(</span> <span class="token string">'todos'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> todos <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token constant">JSON</span> <span class="token punctuation">.</span> <span class="token function">parse</span> <span class="token punctuation">(</span> todos <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
First getTodos
, a function to get Todos data from under local storage. If the todos
does not exist we will return an empty array. Otherwise we will return a javascript object as a string.
const [todos, setTodos] = React.useState(getTodos());
We will use State to re-render every time the todos change the value. The initial value will be called from getTodos
.
1 2 3 4 5 6 | <span class="token keyword">const</span> <span class="token function-variable function">updateTodos</span> <span class="token operator">=</span> <span class="token punctuation">(</span> newTodos <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> stringifiedTodos <span class="token operator">=</span> <span class="token constant">JSON</span> <span class="token punctuation">.</span> <span class="token function">stringify</span> <span class="token punctuation">(</span> newTodos <span class="token punctuation">)</span> <span class="token punctuation">;</span> window <span class="token punctuation">.</span> localStorage <span class="token punctuation">.</span> <span class="token function">setItem</span> <span class="token punctuation">(</span> <span class="token string">'todos'</span> <span class="token punctuation">,</span> stringifiedTodos <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setTodos</span> <span class="token punctuation">(</span> newTodos <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
A function updates the new todos under local storage and sets them in State. We need to use JSON.stringify
in newTodos because local storage only stores strings.
1 2 3 4 5 6 7 | <span class="token keyword">const</span> <span class="token function-variable function">setTodoCompleted</span> <span class="token operator">=</span> <span class="token punctuation">(</span> id <span class="token punctuation">,</span> completed <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> todoIds <span class="token operator">=</span> todos <span class="token punctuation">.</span> <span class="token function">findIndex</span> <span class="token punctuation">(</span> todo <span class="token operator">=></span> todo <span class="token punctuation">.</span> id <span class="token operator">===</span> id <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> newTodos <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token operator">...</span> todos <span class="token punctuation">]</span> <span class="token punctuation">;</span> newTodos <span class="token punctuation">[</span> todoIds <span class="token punctuation">]</span> <span class="token punctuation">.</span> completed <span class="token operator">=</span> completed <span class="token punctuation">;</span> <span class="token function">updateTodos</span> <span class="token punctuation">(</span> newTodos <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
A function to mark Todos is complete. First, we need to retrieve data from the todos
array in State. Next, we will use the array spread syntax to copy the array into a new field so that it doesn’t convert its value. Finally, we update completed
and call updateTodos
to update the new array.
1 2 3 4 5 | <span class="token keyword">const</span> <span class="token function-variable function">addTodo</span> <span class="token operator">=</span> <span class="token punctuation">(</span> label <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> newTodo <span class="token operator">=</span> <span class="token punctuation">{</span> label <span class="token punctuation">,</span> completed <span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> id <span class="token punctuation">:</span> <span class="token function">uuid</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token function">updateTodos</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token operator">...</span> todos <span class="token punctuation">,</span> newTodo <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> |
A function to add a todo to-do list. We need to create a new todo objec via <CreateTodoForm />
. We also set the value to completed = false
and use the uuid()
library to create a unique id for the new todo. and call updateTodos
to append newTodo
to the current todos
network.
The last part returns the todos array and refers to two functions: addTodos
and setTodoCompleted
.
<App />
Component
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">'react'</span> <span class="token punctuation">;</span> <span class="token keyword">import</span> CreateTodoForm <span class="token keyword">from</span> <span class="token string">'./CreateTodoForm'</span> <span class="token punctuation">;</span> <span class="token keyword">import</span> useTodos <span class="token keyword">from</span> <span class="token string">'./useTodos'</span> <span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token string">'./App.css'</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> todos <span class="token punctuation">,</span> addTodo <span class="token punctuation">,</span> setTodoCompleted <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useTodos</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span> div className <span class="token operator">=</span> <span class="token string">"App"</span> <span class="token operator">></span> <span class="token operator"><</span> div className <span class="token operator">=</span> <span class="token string">"todo-container"</span> <span class="token operator">></span> <span class="token operator"><</span> h2 <span class="token operator">></span> Your Todos <span class="token operator"><</span> <span class="token operator">/</span> h2 <span class="token operator">></span> <span class="token operator"><</span> hr <span class="token operator">/</span> <span class="token operator">></span> <span class="token punctuation">{</span> todos <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> todo <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token operator"><</span> div className <span class="token operator">=</span> <span class="token string">"todo"</span> <span class="token operator">></span> <span class="token operator"><</span> p <span class="token operator">></span> <span class="token punctuation">{</span> todo <span class="token punctuation">.</span> label <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> p <span class="token operator">></span> <span class="token operator"><</span> input type <span class="token operator">=</span> <span class="token string">"checkbox"</span> checked <span class="token operator">=</span> <span class="token punctuation">{</span> todo <span class="token punctuation">.</span> completed <span class="token punctuation">}</span> onChange <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setTodoCompleted</span> <span class="token punctuation">(</span> todo <span class="token punctuation">.</span> id <span class="token punctuation">,</span> <span class="token operator">!</span> todo <span class="token punctuation">.</span> completed <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token operator"><</span> CreateTodoForm createNewTodo <span class="token operator">=</span> <span class="token punctuation">{</span> addTodo <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> <span class="token operator">/</span> div <span class="token operator">></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App <span class="token punctuation">;</span> |
App
Component will bring it all together. We will append the items in the todos
and render each item a label and a checkbox. They will perform todos markup completion validation with the onChange
event calling the setTodoCompleted
function in setTodoCompleted
.
Let’s beautify the application form with the following basic styles:
App.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <span class="token selector">.App</span> <span class="token punctuation">{</span> <span class="token property">padding</span> <span class="token punctuation">:</span> 32px <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.todo</span> <span class="token punctuation">{</span> <span class="token property">display</span> <span class="token punctuation">:</span> flex <span class="token punctuation">;</span> <span class="token property">padding</span> <span class="token punctuation">:</span> 8px <span class="token punctuation">;</span> <span class="token property">margin</span> <span class="token punctuation">:</span> 8px <span class="token punctuation">;</span> <span class="token property">background-color</span> <span class="token punctuation">:</span> whitesmoke <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.todo p</span> <span class="token punctuation">{</span> <span class="token property">margin</span> <span class="token punctuation">:</span> 0 <span class="token punctuation">;</span> <span class="token property">margin-right</span> <span class="token punctuation">:</span> 16px <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.create-todo-form</span> <span class="token punctuation">{</span> <span class="token property">text-align</span> <span class="token punctuation">:</span> center <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token selector">.create-todo-form button</span> <span class="token punctuation">{</span> <span class="token property">margin</span> <span class="token punctuation">:</span> 5px <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Everything is ready, we will run the application to check it.
Deploying as a Chrome Extension
Open public/manifest.json
and configure the information for the application as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token punctuation">{</span> <span class="token property">"short_name"</span> <span class="token operator">:</span> <span class="token string">"TodoApp"</span> <span class="token punctuation">,</span> <span class="token property">"name"</span> <span class="token operator">:</span> <span class="token string">"TodoApp Sample"</span> <span class="token punctuation">,</span> <span class="token property">"manifest_version"</span> <span class="token operator">:</span> <span class="token number">2</span> <span class="token punctuation">,</span> <span class="token property">"browser_action"</span> <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"default_popup"</span> <span class="token operator">:</span> <span class="token string">"index.html"</span> <span class="token punctuation">,</span> <span class="token property">"default_title"</span> <span class="token operator">:</span> <span class="token string">"TodoApp"</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token property">"permissions"</span> <span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">"storage"</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token property">"version"</span> <span class="token operator">:</span> <span class="token string">"1.0"</span> <span class="token punctuation">}</span> |
The browser_action.default_popop
attribute will highlight the main page index, the common case would be index.html
. Next we will build the application with the npm run build
from the app’s root directory.
Open Chrome and enter chrome://extensions
. Turn on Developer Mode
at the top right of the browser window and click on Load Unpacked
on the left.
Navigate to the build/
directory and select select. Soon your extension will appear in the list.
Note: The application may not work. Google Chrome policy prevents extensions from being executed inline. To solve this problem, we need to add this line to manifest.json
:
1 2 | "content_security_policy": "script-src 'self' '<your-sha>'; object-src 'self'" |
If your extension encounters an error, return to chrome://extensions
and click on Errors
to see the words Refused to execute inline script...
Rebuild the application and reload it inside the chrome Load unpacked
library Load unpacked
.
Let’s see the results offline:
And now we can create a Google Chrome extension. The world is in your hands, let’s develop good technology applications. Thanks for watching this article. All contributions will be noted and noted for the following articles.
Thanks and Best Regards
References