How to build Google Keep Clone with react JS

We will learn how to build a google keep clone with React and Tailwind. This project will clarify topics like react hooks, props, etc.

 

Google keep clone, google keep, google keep app, code armor
Google keep clone

How to build Google Keep Clone with React JS and Tailwindcss

Hello friends, As you know Google Keep is a top-rated application of Google. Everyone knows it. We keep our little notes in this application. So in this article, we will learn how to build a google keep clone with React and Tailwind. This project will clarify core topics such as react hooks, props, components, and ES6 features. This project contains pure React js and instead of traditional CSS, we will use Tailwind. You can also give your custom style to the application. For beginners, it is the best practice to improve their skills. You can also mention this project in your portfolio. You can check my previous tutorial on how to make a Pokemon App in React | source code

Now let's take a look at the application. This is a simple google keep clone with a dark theme that contains an expandable input box. This input box has two input sections first is for the title and the second one is for the description. It also contains a close button that saves the text you write in the input box. The notes in the application have a custom delete button. And this notes section contains a beautiful masonry layout that increases its user experience.

We understood what this app looked like. Now let's start the project.

Folder structure

To create a good project its folder structure should be good. So let's take a look at the structure of the project. This app has a folder named "src" with files and folders shown below.

The src folder contains the following:-

  • components -(folder)
  • styles -(folder)
  • App.jsx -(file)
  • Mainjsx -(file)

Files inside the "components" folder

  • CreateNote.jsx
  • Header.jsx
  • MyKeep.jsx
  • Notes.jsx

The file inside the "styles" folder

  • tailwind.css

Create these files and folders in your project. Then your folder structure looks like this. You can also see the project structure in the given image.

google keep clone, folder structure, project folder structure, code armor
Structure of src folder

Project set up

If you read our previous article, you know how to set up the project. But if you don't, you just need to create react application. Then install Tailwind and connect it to the app. You can also check our article on how to build a react app using Vite js and tailwind CSS.

Libraries used in the project

This app contains only one external library. This library is used to add icons to the application.

  1. React icons

All set, Now it is time to build our google keep clone.

Building our project

The source code of all files is given below. You need to copy the code and paste it into the files. We will also understand the code shown in every file.

Source code of "main.jsx" file

The primary purpose of giving the code of this file is to connect the "tailwind.css" file.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './styles/tailwind.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

Source code of "App.jsx" file

This file calls the "MyKeep" component.
import React from "react";
import MyKeep from "./components/MyKeep";

function App() {
  return <MyKeep />
}

export default App;

Code of "MyKeep.jsx" file

This is the main file of the google keep clone app which contains all the main logic of the application.
import React from "react";
import Header from "./Header";
import CreateNote from "./CreateNote";
import Notes from "./Notes";
import { useState } from "react";
// import { FaAddressCard } from 'react-icons/fa'

function MyKeep() {
  const [addItem, setAddItem] = useState([]);
  const addNote = (Note) => {
    setAddItem((prev) => {
      return [...prev, Note];
    });
    // console.log(addItem);
  };
  const onDelete = (id) => {
    setAddItem((oldData) =>
      oldData.filter((currentData, index) => {
        return index !== id;
      })
    );
  };

  return (
    <>
      <div className="w-full min-h-screen bg-gray-50 dark:bg-gray-800 font-sans relative">
        <Header></Header>

        <CreateNote passNote={addNote}></CreateNote>
        <div className="columns-3xs gap-3 w-full min-h-full  box-border mx-auto p-4">
         
          {addItem.map((val, index) => {
            return (
              <Notes
                key={index}
                id={index}
                title={val.title}
                content={val.content}
                deleteItem={onDelete}
              ></Notes>
            );
          })}
        </div>
      </div>
    </>
  );
}

export default MyKeep;

Understanding the react source code given above

In the "MyKeep" file the main component is named "MyKeep". This component has the main structure of the application. It calls all other elements such as Header, CreateNote, Notes, etc. These components also have two functions "addNote" and "onDelete".
  1. addNote function:- It takes input data from the "CreateNote" and adds data to the new state variable called "addItem". This all data is passed to the "Notes" component.
  2. onDelete function:- It takes the id of the individual note and removes it from the array stored in the new state variable.
Now let's add code to the other file.

Code of "Header.jsx" file

This is the header of the application. It contains the application name or title. This component calls in the main file.
import React from 'react'

function Header() {
  return (
    <div className='w-full h-10 bg-amber-400 flex  items-center px-5'>
      <div className="font-mono text-white">MyKeep</div>
    </div>
  )
}

export default Header

Code of "CreateNote.jsx" file

This file is responsible for creating notes in the application. Copy the given code and paste it into the "CreateNote.jsx" file. We will understand it later.
import React from "react";
import { useState } from "react";
import { FaBell } from "react-icons/fa";
import { MdColorLens, MdDelete, MdPictureInPicture } from "react-icons/md";

function CreateNote(props) {
  const [currentData, setCurrentData] = useState({
    title: "",
    content: "",
  });

  const [expand, setExpand] = useState(false);

  const handleInputs = (e) => {
    const value = e.target.value;
    const name = e.target.name;
    setCurrentData((pre) => {
      return { ...pre, [name]: value };
    });
  };

  const addEvent = (e) => {
    e.preventDefault();
    if (currentData.title || currentData.content) {
      props.passNote(currentData);
    }
    setCurrentData({
      title: "",
      content: "",
    });

    setExpand(false);
  };

  return (
    <div className="border border-gray-500 shadow-md shadow-gray-900 w-[28rem] min-h-36 rounded-md mx-auto my-6">
      <form className="w-full h-full p-2.5">
        {expand ? (
          <input
            type="text"
            value={currentData.title}
            name="title"
            onChange={handleInputs}
            placeholder="Title"
            className="w-full font-medium text-lg dark:text-gray-300 bg-transparent outline-none"
            autoComplete="false"
          />
        ) : null}

        <textarea
          name="content"
          value={currentData.content}
          onChange={handleInputs}
          onClick={() => {
            setExpand(true);
          }}
          cols="auto"
          rows="auto"
          className="w-full resize-x-none bg-transparent text-base font-medium dark:text-gray-300 border-none outline-none transition"
          style={
            expand
              ? { height: "3rem", marginTop: "0.75rem" }
              : { height: "1.5rem", marginTop: 0 }
          }
          placeholder="Take a note..."
        ></textarea>

        {expand ? (
          <div className="w-full  flex justify-between items-center">
            <div className="flex dark:text-gray-400 gap-5">
              <FaBell className="hover:bg-gray-500 hover:bg-opacity-40 w-6 h-6 rounded-full p-1" />
              <MdColorLens className="hover:bg-gray-500 hover:bg-opacity-40 w-6 h-6 rounded-full p-1" />
              <MdPictureInPicture className="hover:bg-gray-500 hover:bg-opacity-40 w-6 h-6 rounded-full p-1" />
              <MdDelete className="hover:bg-gray-500 hover:bg-opacity-40 w-6 h-6 rounded-full p-1" />
            </div>

            <button
              onClick={addEvent}
              className=" px-8 dark:text-gray-300 font-medium"
            >
              Close
            </button>
          </div>
        ) : null}
      </form>
    </div>
  );
}

export default CreateNote;

Understanding the code

This component has a box. This box has two input fields and one close button. The one input field takes the title as input and the second one takes content as input. At starting this box contract. And when you click on the title, it will expand and trigger a function named "handleInputs". This function stores the title and content's value in the new state variable named "currenData"

On clicking the "close" button, it also triggers a function named "addEvent". This function will pass all the input data to the main file. Then it removes all the text from the "currentData" state variable and contracts the box.

Code of "Notes.jsx" file

import React from "react";
import { MdColorLens, MdDelete } from "react-icons/md";

function Notes({ id, title, content, deleteItem }) {
  const deleteNote = () => {
    deleteItem(id);
  };

  return (
    <div className="border border-gray-400 w-auto rounded-md min-h-[6rem] max-h-fit p-2 hover:shadow-lg hover:shadow-gray-900 mb-3 break-inside-avoid">
      <div className="w-full font-medium text-lg dark:text-gray-300 bg-transparent">
        {title}
      </div>
      <div className="w-full h-15 resize-x-none bg-transparent text-base font-medium dark:text-gray-400">
        {content}
      </div>

      <div className="w-full  flex justify-end items-center">
        <div className="flex dark:text-gray-400 gap-1">
          <MdColorLens className="hover:bg-gray-500 hover:bg-opacity-40 w-6 h-6 rounded-full p-1" />
          <MdDelete
            onClick={deleteNote}
            className="hover:bg-gray-500 hover:bg-opacity-40 w-6 h-6 rounded-full p-1 cursor-pointer"
          />
        </div>
      </div>
    </div>
  );
}

export default Notes;

Understanding the code

It contains a note box. We fetch data in it from the state variable and return the note box with the data. It has also a delete button that passes the box id to the main file. And main file code will delete the targeted note. In the main file, we stored all the data in an array. And we call this component for every data by using the array map method.

Hurray, we completed our google keep clone. Now run it and enjoy the code.

Conclusion

This is a great project for learning. It covers various topics like object destructuring, react hooks, components, props, and much more. I am sure you learned something new from the google keep clone. If you do so. Please share this article with your friends, teachers, and groups.

If you have any queries tell us in the comment section. We do our best to remove your queries. You can also request any project for yourself.

Thanks !!!

About the Author

Code Armor makes Full Stack Development easy. We provide code projects with live examples and source code. We help you to increase your coding skills and problem-solving skills. We provide you with code projects in technologies like HTML, CSS, JavaS…

تعليق واحد

  1. Comment topics for more articles
Cookie Consent
We serve cookies on this site to analyze traffic, remember your preferences, and optimize your experience.
Oops!
It seems there is something wrong with your internet connection. Please connect to the internet and start browsing again.
AdBlock Detected!
We have detected that you are using adblocking plugin in your browser.
The revenue we earn by the advertisements is used to manage this website, we request you to whitelist our website in your adblocking plugin.
Site is Blocked
Sorry! This site is not available in your country.