<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Spruce Emmanuel - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Spruce Emmanuel - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:29:41 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/Spruce/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Go From Hello World to Building Real-World Applications ]]>
                </title>
                <description>
                    <![CDATA[ Many developers start learning programming by building simple projects like todo apps, calculators, and basic CRUD applications. These projects are useful at the beginning, as they help you understand how a programming language works and give you the... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-go-from-hello-world-to-building-real-world-applications/</link>
                <guid isPermaLink="false">697d098607632dbd100433e8</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Beginner Developers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Learning Journey ]]>
                    </category>
                
                    <category>
                        <![CDATA[ coding ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Fri, 30 Jan 2026 19:41:58 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769802056548/2b1b2ede-5f7f-423f-b6ee-19e0c0ac7b43.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Many developers start learning programming by building simple projects like todo apps, calculators, and basic CRUD applications. These projects are useful at the beginning, as they help you understand how a programming language works and give you the confidence to start building things. But for many developers, progress stops there.</p>
<p>Real world applications aren’t just about showing data on a screen. They solve real problems, work with real users, and handle situations that don’t always go as planned. This is where many developers struggle.</p>
<p>When I review junior developers’ résumés, I notice a common pattern: the projects section is often filled with beginner apps that look very similar. In today’s job market, this is usually not enough. Employers want to see that you can build something useful, something people would actually use.</p>
<p>The goal of this article is to help you move past simple Hello World projects like todo apps, calculators, and basic CRUD applications. By the end, you’ll understand how to approach building real applications that solve real problems and feel closer to what is built in the real world.</p>
<p>You might be wondering why you should listen to me.</p>
<p>Over the last 10 years, I’ve spent a lot of time building, breaking, and rebuilding software. I have experimented, failed many times, and eventually built applications that thousands of people use every day. A few weeks ago, I launched one of my own SaaS products and watched real users use it at scale, with over a thousand active users during peak hours, without the system crashing.</p>
<p>I’m sharing this because I’ve been where you are now.</p>
<p>If you continue reading, you will:</p>
<ul>
<li><p>Learn from real experience building applications used by real users</p>
</li>
<li><p>Learn what not to do, based on years of mistakes and lessons</p>
</li>
<li><p>Learn what actually works and what helps you stand out as a junior developer</p>
</li>
<li><p>Clear up common misconceptions that slow people down</p>
</li>
</ul>
<p>This article is not about theory. It’s about building real things.</p>
<p>To drive this point home, we’ll build a real world application that solves a real problem and is used by real people. Along the way, you’ll learn how to come up with real application ideas, how to build them with simple tools, and how to serve them to many users.</p>
<p>If this sounds like something you’re up for, then let’s get started.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-you-probably-think-you-dont-know-enough">You Probably Think You Don’t Know Enough</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-find-real-world-application-ideas">How to Find Real World Application Ideas</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-we-going-to-build">What Are We Going to Build</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-1-setting-up-the-backend">Step 1: Setting Up the Backend</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-adding-background-removal-to-the-backend">Step 2: Adding Background Removal to the Backend</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-building-the-frontend">Step 3: Building the Frontend</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-running-and-testing-the-application-locally">Running and Testing the Application Locally</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-putting-the-backend-on-the-internet">Step 4: Putting the Backend on the Internet</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-deploying-the-backend-on-cloud-run">Deploying the Backend on Cloud Run</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-updating-the-frontend-to-use-the-live-backend">Updating the Frontend to Use the Live Backend</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-making-the-backend-and-frontend-work-together-cors">Step 5: Making the Backend and Frontend Work Together CORS</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-putting-the-frontend-on-the-internet">Step 6: Putting the Frontend on the Internet</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts-what-you-just-built-matters">Final Thoughts What You Just Built Matters</a></p>
</li>
</ol>
<h2 id="heading-you-probably-think-you-dont-know-enough"><strong>You Probably Think You Don't Know Enough</strong></h2>
<p>Before we begin, I want to clear up the most common misconception beginners have.</p>
<p>Many developers believe they don’t know enough to start building real world applications. They think they need to learn more JavaScript, more Python, or another framework before they are ready. Some even think learning React is the final step that will suddenly make everything click.</p>
<p>This belief is very common, but it’s not true.</p>
<p>If you know how to write HTML, CSS, and a simple loop or function in any programming language, you already have most of what it takes to build a real world application. This tutorial is proof of that.</p>
<p>That’s why I am writing this article. Not to tell you to learn more first, but to show you how far you can go with what you already know.</p>
<h2 id="heading-how-to-find-real-world-application-ideas">How to Find Real World Application Ideas</h2>
<p>One question beginners ask a lot is, “What kind of apps should I build?”</p>
<p>This is rarely talked about, but it matters more than most people think.</p>
<p>A simple rule is this: build things that already exist.</p>
<p>Look at the apps you use every day, especially the simple ones. Tools that do one thing well. If you find yourself using an app often, that app is solving a real problem.</p>
<p>For example, people use background removers to clean up images. They use URL shorteners to share links. They use notes apps to save quick thoughts. None of these ideas are new, but they are real.</p>
<p>You don’t need to invent something original. You need to understand a problem and build a working solution for it.</p>
<p>When you replicate real tools, you naturally learn how real applications are structured. You also end up with projects that make sense on a résumé, because they solve problems people recognize.</p>
<p>That’s exactly what we are going to do in this tutorial.</p>
<h2 id="heading-what-are-we-going-to-build">What Are We Going to Build?</h2>
<p>I’ll tell you now, it is not going to be another Hello World application. We’re going to be building a background remover web application.</p>
<p>This is the kind of tool people actually use. Designers use it for images, content creators use it for thumbnails, and developers build similar features into real products. It works with real files, real data, and real results.</p>
<p>If you want to see the final result before we start building, you can try the working app here: <a target="_blank" href="https://iamspruce.github.io/background-remover/">https://iamspruce.github.io/background-remover/</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769502551999/c2bdf45f-8768-4dc8-a816-6fa9a05dc15b.png" alt="The background remover application we are about to build" class="image--center mx-auto" width="2614" height="1848" loading="lazy"></p>
<p>We’ll build this app using simple tools on purpose. Plain HTML, CSS, and JavaScript for the frontend, and Python for the backend. No heavy frameworks and no complicated setup.</p>
<p>Before we continue, let me clear up <strong>another common misconception.</strong></p>
<p>Many developers believe that for an application to be taken seriously, it must be built with complex frameworks. In my experience building applications for clients around the world over the last 10 years, not a single client has ever asked me what framework I used.</p>
<p>They only cared about one thing: Did it work, and did it solve their problem?</p>
<p>Users won’t care how your app is built. They care that it works. If HTML, CSS, and JavaScript can solve the problem, there’s no reason to wait months just to learn a new framework.</p>
<p>Now that we understand <em>why</em> we’re building this app and <em>what</em> problem it solves, it’s time to start writing code.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we start writing code, let’s quickly talk about what you need.</p>
<p>This tutorial is not for absolute beginners, but it’s also not super advanced. If you’ve built small things before and you want to build something that actually feels real, you’re in the right place.</p>
<h3 id="heading-what-you-should-already-know">What You Should Already Know</h3>
<p>You should be comfortable with:</p>
<ul>
<li><p>Basic HTML: You know what inputs, buttons, images, and divs do.</p>
</li>
<li><p>Basic CSS: You can style a page and make it look presentable.</p>
</li>
<li><p>Basic JavaScript: You know how to listen for a button click and send a request using <code>fetch</code>.</p>
</li>
</ul>
<p>That’s enough to follow along.</p>
<p>You don’t need React or any other frontend framework.</p>
<h3 id="heading-backend-knowledge">Backend Knowledge</h3>
<p>For the backend, you don’t need to be a Python expert.</p>
<p>You just need to understand that:</p>
<ul>
<li><p>Python can run a server</p>
</li>
<li><p>A server can receive requests</p>
</li>
<li><p>A server can send back responses</p>
</li>
</ul>
<p>Everything else will be explained as we go.</p>
<h3 id="heading-tools-you-need">Tools You Need</h3>
<p>Make sure you have these installed:</p>
<ul>
<li><p>Python 3.9 or newer</p>
</li>
<li><p>Git</p>
</li>
<li><p>A code editor like VS Code</p>
</li>
<li><p>A browser</p>
</li>
</ul>
<p>No Docker knowledge or cloud experience required.</p>
<h3 id="heading-github-account-important">GitHub Account (Important)</h3>
<p>We’ll deploy the backend directly from GitHub, so you’ll need a GitHub account.</p>
<p>If you’ve never pushed a project to GitHub or hosted one before, I’ve already written a <a target="_blank" href="https://www.freecodecamp.org/news/host-your-first-project-on-github/">beginner-friendly guide</a> you can follow first.</p>
<p>Read that article, then come back here.</p>
<h3 id="heading-a-quick-mindset-check">A Quick Mindset Check</h3>
<p>This is not a copy-paste tutorial. You will see real errors. Things may break. That’s normal. That’s how real applications are built.</p>
<p>Now that we’re clear on what you need, let’s start writing code.</p>
<p>We’ll begin with the backend. This is an important decision, so let’s explain it properly.</p>
<h2 id="heading-step-1-setting-up-the-backend">Step 1: Setting Up the Backend</h2>
<h3 id="heading-what-is-a-backend-and-why-do-we-need-one">What Is a Backend and Why Do We Need One?</h3>
<p>A backend is a program that runs on a server and does the heavy work for an application.</p>
<p>In our case, the heavy work is image processing. Removing a background from an image requires libraries that can’t run inside the browser. Browsers are designed for safety and user interaction, not for this kind of processing.</p>
<p>That’s why we need a backend.</p>
<p>The backend will:</p>
<ul>
<li><p>Receive an image from the user</p>
</li>
<li><p>Remove the background</p>
</li>
<li><p>Send the processed image back</p>
</li>
</ul>
<p>The frontend will simply talk to this backend later.</p>
<h3 id="heading-keeping-things-simple-on-purpose">Keeping Things Simple on Purpose</h3>
<p>Because this might be your first real project, we’re going to keep the backend as simple as possible.</p>
<ul>
<li><p>One programming language (Python)</p>
</li>
<li><p>One backend file</p>
</li>
<li><p>No complex folder structure</p>
</li>
<li><p>No advanced concepts</p>
</li>
</ul>
<p>This is intentional. Real world applications don’t have to start out complex. They typically start small and grow.</p>
<h3 id="heading-project-structure">Project Structure</h3>
<p>Create a new folder called:</p>
<pre><code class="lang-bash">background-remover
</code></pre>
<p>Inside it, create a folder for the backend:</p>
<pre><code class="lang-bash">background-remover/
  backend/
</code></pre>
<p>Move into the backend folder:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> background-remover/backend
</code></pre>
<p>Now create a virtual environment:</p>
<pre><code class="lang-bash">python -m venv env
</code></pre>
<p>A virtual environment keeps this project’s dependencies separate from everything else on your computer. This is standard practice and something you’ll see in real projects.</p>
<p>Now activate it:</p>
<p>macOS or Linux:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">source</span> env/bin/activate
</code></pre>
<p>Windows:</p>
<pre><code class="lang-bash">env\Scripts\activate
</code></pre>
<p>Now create a folder for your application code:</p>
<pre><code class="lang-bash">mkdir api
</code></pre>
<p>Your structure should now look like this:</p>
<pre><code class="lang-bash">background-remover/
  backend/
    env/
    api/
</code></pre>
<p>At this stage, nothing looks impressive yet. That’s normal.</p>
<h3 id="heading-installing-fastapi">Installing FastAPI</h3>
<p>We’ll use FastAPI to build the backend API.</p>
<p>Install it together with Uvicorn, which is the server that runs our app:</p>
<pre><code class="lang-bash">pip install fastapi uvicorn
</code></pre>
<p>FastAPI allows us to define endpoints clearly and with very little code, which is perfect for us.</p>
<h3 id="heading-creating-the-first-backend-file">Creating the First Backend File</h3>
<p>Inside the <code>api</code> folder, create a file called <code>main.py</code>.</p>
<p>Add the following code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> fastapi <span class="hljs-keyword">import</span> FastAPI

app = FastAPI()

<span class="hljs-meta">@app.get("/health")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">health</span>():</span>
    <span class="hljs-keyword">return</span> {<span class="hljs-string">"status"</span>: <span class="hljs-string">"ok"</span>}
</code></pre>
<p>Let’s pause and understand what this does.</p>
<ul>
<li><p>We created a FastAPI application</p>
</li>
<li><p>We added a <code>/health</code> endpoint</p>
</li>
<li><p>This endpoint simply returns a message</p>
</li>
</ul>
<p>Before building real features, developers always confirm that their server actually runs. That is exactly what this endpoint is for.</p>
<h3 id="heading-running-the-server">Running the Server</h3>
<p>From inside the <code>backend</code> folder, start the server:</p>
<pre><code class="lang-bash">uvicorn api.main:app --reload
</code></pre>
<p>Now open a new terminal and run:</p>
<pre><code class="lang-bash">curl http://localhost:8000/health
</code></pre>
<p>You should see:</p>
<pre><code class="lang-bash">{<span class="hljs-string">"status"</span>:<span class="hljs-string">"ok"</span>}
</code></pre>
<p>This is an important moment.</p>
<p>You now have:</p>
<ul>
<li><p>A running backend server</p>
</li>
<li><p>A real HTTP endpoint</p>
</li>
<li><p>A response coming from your own code</p>
</li>
</ul>
<p>This is how real backend services start.</p>
<h3 id="heading-why-we-did-this-first">Why We Did This First</h3>
<p>At this point, you might wonder why we didn’t jump straight into background removal.</p>
<p>The reason is simple: if the server doesn’t run, nothing else matters.</p>
<p>By starting with a health endpoint, we removed uncertainty. We know the server works. Everything we add next is built on top of something we already know is working.</p>
<p>Now that the foundation is in place, we can move on to the real feature.</p>
<h2 id="heading-step-2-adding-background-removal-to-the-backend">Step 2: Adding Background Removal to the Backend</h2>
<p>Before we write any code here, we need to clear up an important misconception.</p>
<h3 id="heading-a-common-misconception-about-machine-learning">A Common Misconception About Machine Learning</h3>
<p>When people hear “background removal,” they often think machine learning is too advanced for them.</p>
<p>In real world development, this is almost never how it works.</p>
<p>You aren’t expected to build machine learning models yourself. You use libraries created by others and focus on integrating them correctly.</p>
<p>That is exactly what we’re doing here.</p>
<h3 id="heading-installing-the-background-removal-library">Installing the Background Removal Library</h3>
<p>Install the required packages:</p>
<pre><code class="lang-bash">pip install rembg pillow onnxruntime
</code></pre>
<ul>
<li><p><code>rembg</code> handles the background removal</p>
</li>
<li><p><code>pillow</code> helps us work with images</p>
</li>
</ul>
<p>For our purposes here, you don’t need to understand how these libraries work internally. You only need to know how to use them.</p>
<h3 id="heading-adding-the-background-removal-endpoint">Adding the Background Removal Endpoint</h3>
<p>Now update <code>main.py</code> so it looks like this:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> fastapi <span class="hljs-keyword">import</span> FastAPI, UploadFile, File
<span class="hljs-keyword">from</span> rembg <span class="hljs-keyword">import</span> remove
<span class="hljs-keyword">from</span> PIL <span class="hljs-keyword">import</span> Image
<span class="hljs-keyword">import</span> io

app = FastAPI()

<span class="hljs-meta">@app.get("/health")</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">health</span>():</span>
    <span class="hljs-keyword">return</span> {<span class="hljs-string">"status"</span>: <span class="hljs-string">"ok"</span>}

<span class="hljs-meta">@app.post("/remove-bg")</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">remove_bg</span>(<span class="hljs-params">file: UploadFile = File(<span class="hljs-params">...</span>)</span>):</span>
    image_bytes = <span class="hljs-keyword">await</span> file.read()
    image = Image.open(io.BytesIO(image_bytes))

    output = remove(image)

    buffer = io.BytesIO()
    output.save(buffer, format=<span class="hljs-string">"PNG"</span>)
    buffer.seek(<span class="hljs-number">0</span>)

    <span class="hljs-keyword">return</span> buffer.getvalue()
</code></pre>
<p>Let’s explain this carefully.</p>
<ul>
<li><p>The endpoint accepts an uploaded image</p>
</li>
<li><p>The image is read into memory</p>
</li>
<li><p>The background is removed</p>
</li>
<li><p>The result is saved as a PNG with transparency</p>
</li>
<li><p>The image is returned to the client</p>
</li>
</ul>
<p>This endpoint is the core of our application.</p>
<h3 id="heading-testing-the-endpoint-with-curl">Testing the Endpoint With curl</h3>
<p>Before building the frontend, we’ll test the backend directly.</p>
<p>Run this command:</p>
<pre><code class="lang-javascript">curl -X POST \
  -F <span class="hljs-string">"file=@person.jpg"</span> \
  <span class="hljs-attr">http</span>:<span class="hljs-comment">//localhost:8000/remove-bg \</span>
  --output result.png
</code></pre>
<p>Open <code>result.png</code>. If you see the background removed, then the backend is complete.</p>
<p>At this point, you have built a backend that:</p>
<ul>
<li><p>Accepts real user input</p>
</li>
<li><p>Processes real data</p>
</li>
<li><p>Returns a meaningful result</p>
</li>
</ul>
<p>This is a real backend.</p>
<h3 id="heading-where-we-are-now">Where We Are Now</h3>
<p>Let’s pause and summarize:</p>
<ul>
<li><p>We set up a backend server</p>
</li>
<li><p>We confirmed that it runs</p>
</li>
<li><p>We added a real feature</p>
</li>
<li><p>We tested it without a frontend</p>
</li>
</ul>
<p>This is exactly how real developers work.</p>
<p>In the next section, we’ll build a simple frontend that talks to this backend and turns it into something users can interact with.</p>
<h2 id="heading-step-3-building-the-frontend-what-the-user-actually-sees">Step 3: Building the Frontend (What the User Actually Sees)</h2>
<p>At this point, our backend is working.</p>
<p>It can receive an image, remove the background, and send the result back. But right now, only developers can use it, because it requires terminal commands.</p>
<p>To make this useful to actual (non-technical) people, we need a frontend.</p>
<p>The frontend is simply the part of the application users see and interact with in their browser.</p>
<h3 id="heading-clearing-a-common-misconception-about-frontends">Clearing a Common Misconception About Frontends</h3>
<p>Many beginners think building a frontend means learning a framework first.</p>
<p>This is not true.</p>
<p>Frameworks help later, but they aren’t required to build real applications. Under the hood, every frontend still comes down to HTML, CSS, and JavaScript.</p>
<p>That’s why we are using plain HTML, CSS, and JavaScript here. No React, no build tools, no setup. Just the basics.</p>
<h3 id="heading-what-our-frontend-will-do">What Our Frontend Will Do</h3>
<p>Our frontend has one job. It will:</p>
<ul>
<li><p>Let the user select an image</p>
</li>
<li><p>Send that image to the backend</p>
</li>
<li><p>Receive the processed image</p>
</li>
<li><p>Show it on the screen</p>
</li>
<li><p>Allow the user to download it</p>
</li>
</ul>
<p>That’s all.</p>
<p>If it does these things correctly, it’s a real frontend.</p>
<h3 id="heading-creating-the-frontend">Creating the Frontend</h3>
<p>Go back to the root of your project and create three files:</p>
<pre><code class="lang-bash">index.html
styles.css
app.js
</code></pre>
<p>This simple setup is very common. Each file has a clear responsibility, which makes the code easier to understand.</p>
<h3 id="heading-writing-the-html-page">Writing the HTML Page</h3>
<p>Open <code>index.html</code> and add the following:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Background Remover<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"styles.css"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Background Remover<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"file"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"imageInput"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"removeBtn"</span>&gt;</span>Remove Background<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"result"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"resultImage"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"downloadLink"</span> <span class="hljs-attr">download</span>&gt;</span>Download Image<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"app.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Right now, this page won’t do anything interesting. That’s expected.</p>
<p>HTML only describes what should be on the page. The behavior comes from JavaScript, which we’ll add after we add some styling.</p>
<h3 id="heading-adding-some-basic-styling">Adding Some Basic Styling</h3>
<p>Open <code>styles.css</code> and add this:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: sans-serif;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">600px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">40px</span> auto;
}

<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-selector-class">.result</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-selector-id">#downloadLink</span> {
  <span class="hljs-attribute">display</span>: none;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<p>This is not about making things look fancy.</p>
<p>The goal here is simply to make the page readable and pleasant to use. Many real internal tools look no better than this. (And you can always improve the styling later if you want.)</p>
<h3 id="heading-connecting-the-frontend-to-the-backend">Connecting the Frontend to the Backend</h3>
<p>Now we’ll write the JavaScript that makes everything work.</p>
<p>Open <code>app.js</code> and add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> imageInput = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"imageInput"</span>);
<span class="hljs-keyword">const</span> removeBtn = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"removeBtn"</span>);
<span class="hljs-keyword">const</span> resultImage = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"resultImage"</span>);
<span class="hljs-keyword">const</span> downloadLink = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"downloadLink"</span>);

removeBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> file = imageInput.files[<span class="hljs-number">0</span>];

  <span class="hljs-keyword">if</span> (!file) {
    <span class="hljs-keyword">return</span>;
  }

  <span class="hljs-keyword">const</span> formData = <span class="hljs-keyword">new</span> FormData();
  formData.append(<span class="hljs-string">"file"</span>, file);

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"http://localhost:8000/remove-bg"</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
    <span class="hljs-attr">body</span>: formData,
  });

  <span class="hljs-keyword">const</span> blob = <span class="hljs-keyword">await</span> response.blob();
  <span class="hljs-keyword">const</span> imageUrl = URL.createObjectURL(blob);

  resultImage.src = imageUrl;
  downloadLink.href = imageUrl;
  downloadLink.style.display = <span class="hljs-string">"inline"</span>;
});
</code></pre>
<p>Let’s slow down and explain what’s happening here:</p>
<ul>
<li><p>We read the image selected by the user</p>
</li>
<li><p>We wrap it in <code>FormData</code> so it can be sent to the backend</p>
</li>
<li><p>We send it to our <code>/remove-bg</code> endpoint</p>
</li>
<li><p>We receive the processed image back</p>
</li>
<li><p>We display it and prepare it for download</p>
</li>
</ul>
<p>This is the moment where the frontend and backend finally talk to each other.</p>
<h3 id="heading-running-the-frontend-with-live-server">Running the Frontend With Live Server</h3>
<p>Before testing, make sure your backend is still running.</p>
<p>Now, instead of opening <code>index.html</code> directly, use the <strong>Live Server</strong> extension in VS Code.</p>
<p>If you don’t have it installed, just open VS Code extensions, search for “Live Server”, and then install it. Then right click on <code>index.html</code> and click “Open with Live Server”.</p>
<p>This starts a small local server for the frontend.</p>
<p>Why does this matter?</p>
<p>Many browser features work better when files are served through a server instead of opened directly from the file system. Using Live Server also matches how real frontends are served.</p>
<h3 id="heading-testing-the-full-application-locally">Testing the Full Application Locally</h3>
<p>Now choose an image and click the button.</p>
<p>If everything is working:</p>
<ul>
<li><p>The image is sent to the backend</p>
</li>
<li><p>The background is removed</p>
</li>
<li><p>The result appears on the page</p>
</li>
<li><p>The download link shows up</p>
</li>
</ul>
<p>Take a moment here. You have just built:</p>
<ul>
<li><p>A backend that processes real data</p>
</li>
<li><p>A frontend that talks to it</p>
</li>
<li><p>A complete application running locally</p>
</li>
</ul>
<p>This is already more than a “Hello World” project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769503437045/6a984e58-cee9-4255-84aa-76ee26b805b3.png" alt="The application running locally after connecting the frontend and backend and removing background from an image" class="image--center mx-auto" width="2614" height="1848" loading="lazy"></p>
<h3 id="heading-clearing-one-more-misconception">Clearing One More Misconception</h3>
<p>Some beginners look at this and think: “This feels too simple to be a real app.”</p>
<p>This is another misconception. Real applications aren’t defined by complexity. They’re defined by usefulness. If your app solves a real problem and people can use it, it’s a real application.</p>
<p>In the next section, we’ll take this exact app and put it on the internet so anyone can use it.</p>
<h2 id="heading-step-4-putting-the-backend-on-the-internet">Step 4: Putting the Backend on the Internet</h2>
<p>Right now, your backend is running on your computer.</p>
<p>That means:</p>
<ul>
<li><p>It works only for you</p>
</li>
<li><p>If you close your laptop, it stops</p>
</li>
<li><p>If someone opens your frontend, it cannot reach your backend</p>
</li>
</ul>
<p>To fix this, we need to run the backend on a computer that is <strong>always online</strong>.</p>
<p>This process is called <strong>deployment</strong>.</p>
<h3 id="heading-a-simple-way-to-think-about-deployment">A Simple Way to Think About Deployment</h3>
<p>Deployment does <strong>not</strong> mean writing new code.</p>
<p>It simply means this: instead of running your backend on your laptop, you run it on another computer that never sleeps.</p>
<p>Everything we do next exists only to make that happen.</p>
<h3 id="heading-why-we-arent-using-netlify-or-vercel">Why We Aren’t Using Netlify or Vercel</h3>
<p>You might be wondering why we aren’t using Netlify or Vercel. Those platforms are great, but they’re mainly for <strong>frontends</strong>.</p>
<p>They work best when your app is:</p>
<ul>
<li><p>Static HTML, CSS, and JavaScript</p>
</li>
<li><p>A frontend framework like React or Vue</p>
</li>
<li><p>Small serverless functions</p>
</li>
</ul>
<p>Our backend is different. It’s a <strong>Python server</strong> that:</p>
<ul>
<li><p>Stays running</p>
</li>
<li><p>Accepts image uploads</p>
</li>
<li><p>Processes images</p>
</li>
<li><p>Uses heavy native libraries for background removal</p>
</li>
</ul>
<p>This kind of backend needs a <strong>real server</strong>, not a lightweight serverless function.</p>
<p>That’s why Netlify and Vercel aren’t a good fit here.</p>
<h3 id="heading-why-were-using-cloud-run">Why We’re Using Cloud Run</h3>
<p>Instead, we’re using <strong>Cloud Run</strong>.</p>
<p>Cloud Run lets us run real backend servers on Google’s infrastructure without managing servers ourselves.</p>
<p>We’re using it because:</p>
<ul>
<li><p>It supports full Python backends</p>
</li>
<li><p>It deploys directly from GitHub</p>
</li>
<li><p>It handles scaling and servers for us</p>
</li>
<li><p>It works well with heavy workloads</p>
</li>
<li><p>It’s beginner-friendly</p>
</li>
</ul>
<p>Most importantly, it lets you deploy a <strong>real backend</strong> without learning cloud commands or CI/CD pipelines.</p>
<h3 id="heading-preparing-the-backend-for-cloud-run">Preparing the Backend for Cloud Run</h3>
<p>Before deploying, we need to make sure our backend is ready.</p>
<h4 id="heading-creating-requirementstxt">Creating <code>requirements.txt</code></h4>
<p>Inside the <code>backend</code> folder, create a file called <code>requirements.txt</code>.</p>
<p>Add this:</p>
<pre><code class="lang-go">fastapi
uvicorn
rembg
pillow
onnxruntime
</code></pre>
<p>This file tells Cloud Run which Python libraries to install.</p>
<h3 id="heading-creating-a-github-repository">Creating a GitHub Repository</h3>
<p>Cloud Run deploys directly from GitHub, so our code must live there.</p>
<p>From the project root, run:</p>
<pre><code class="lang-go">git init
git add .
git commit -m <span class="hljs-string">"Initial background remover project"</span>
git branch -M main
git remote add origin YOUR_REPO_URL
git push -u origin main
</code></pre>
<p>This <strong>single repository</strong> will be used for both backend and frontend.</p>
<h3 id="heading-deploying-the-backend-on-cloud-run">Deploying the Backend on Cloud Run</h3>
<p>Now open your browser and go to <strong>Google Cloud Console</strong>.</p>
<h4 id="heading-1-create-a-new-project">1. Create a New Project</h4>
<p>Open <a target="_blank" href="https://console.cloud.google.com">Google Cloud Console</a> and click New Project. Give it a name (for example: <code>background-remover</code>) and then click Create.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769749541636/778464de-2c95-4f7e-9505-9729a84f2001.png" alt="Creating a new Google Cloud project" class="image--center mx-auto" width="2614" height="1848" loading="lazy"></p>
<h4 id="heading-2-open-cloud-run">2. Open Cloud Run</h4>
<p>Use the search bar at the top and search for <strong>Cloud Run.</strong> Then open it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769749581066/9078ae2e-fa00-4dfa-be04-383d9702bb90.png" alt="Cloud Run overview page" class="image--center mx-auto" width="2614" height="1848" loading="lazy"></p>
<p>Cloud Run will automatically enable the required APIs.</p>
<p>You will be asked to set up billing. Google gives you $300 free credit, which is more than enough for this tutorial.</p>
<h4 id="heading-3-start-creating-the-service">3. Start Creating the Service</h4>
<p>Click Create Service and choose Deploy continuously from a repository.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769749636809/348f720a-b1b1-46e4-9eab-48928adeb2f3.png" alt="Creating a Cloud Run service from a repository" class="image--center mx-auto" width="2614" height="1848" loading="lazy"></p>
<h4 id="heading-4-connect-your-github-account">4. Connect Your GitHub Account</h4>
<p>Select <strong>GitHub</strong> as the repository provider and authenticate your GitHub account. Then install Google Cloud Build on your GitHub account. Choose <strong>only the repository</strong> you want to deploy.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769749686780/89571b5e-0bd7-4127-82d2-b9445a5044e4.png" alt="Installing Google Cloud Build on GitHub" class="image--center mx-auto" width="2272" height="1664" loading="lazy"></p>
<p>This allows Google Cloud to build and deploy your code automatically.</p>
<h4 id="heading-5-select-the-repository">5. Select the Repository</h4>
<p>Then choose the repository you just installed Cloud Build on and select the <code>main</code> branch.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769749745522/a9f95c4b-7fd3-480d-bae1-7ae92bcdd52f.png" alt="Selecting the GitHub repository" class="image--center mx-auto" width="2614" height="1848" loading="lazy"></p>
<h4 id="heading-6-configure-the-build">6. Configure the Build</h4>
<p>Now comes the important part: building the context directory.</p>
<p>Set this to:</p>
<pre><code class="lang-bash">backend
</code></pre>
<p>This tells Cloud Run:</p>
<blockquote>
<p>“My backend code lives inside the <code>backend</code> folder.”</p>
</blockquote>
<p>For the entry command, enter:</p>
<pre><code class="lang-bash">uvicorn api.main:app --host 0.0.0.0 --port 8080
</code></pre>
<p>This is how Cloud Run starts your FastAPI server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769749801126/87676cce-3e75-4244-b32f-401f782d7c85.png" alt="Build configuration for the backend" class="image--center mx-auto" width="2614" height="1848" loading="lazy"></p>
<h4 id="heading-7-configure-container-resources">7. Configure Container Resources</h4>
<p>Our backend runs a <strong>background-removal model</strong>, which is heavy.</p>
<p>So we must increase resources.</p>
<ul>
<li><p>Change memory from <strong>512 MB → 2 GB</strong></p>
</li>
<li><p>Set CPU to <strong>4</strong></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769749870471/a24e5d37-af21-48a6-b720-b6748d478b6d.png" alt="Increasing memory and CPU" class="image--center mx-auto" width="2614" height="1848" loading="lazy"></p>
<p>This ensures the model can load and run properly.</p>
<h4 id="heading-8-deploy">8. Deploy</h4>
<p>Now click <strong>Create</strong>.</p>
<p>Cloud Run will:</p>
<ul>
<li><p>Build your app</p>
</li>
<li><p>Install dependencies</p>
</li>
<li><p>Create a container</p>
</li>
<li><p>Deploy it to the internet</p>
</li>
</ul>
<p>You’ll see logs showing the build and deployment process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1769749916316/5eb276f6-01c1-413c-aeb7-13a8d34dbbe2.png" alt="Cloud Build running" class="image--center mx-auto" width="2614" height="1848" loading="lazy"></p>
<p>This can take a few minutes. That’s normal.</p>
<h3 id="heading-checking-that-the-backend-is-live">Checking That the Backend Is Live</h3>
<p>Once deployment finishes, Cloud Run will show you a <strong>public URL</strong>.</p>
<p>Test it:</p>
<pre><code class="lang-bash">curl https://YOUR_CLOUD_RUN_URL/health
</code></pre>
<p>If you see:</p>
<pre><code class="lang-bash">{<span class="hljs-string">"status"</span>:<span class="hljs-string">"ok"</span>}
</code></pre>
<p>Your backend is officially live on the internet.</p>
<p>Pause here for a second.</p>
<p>You just deployed a real backend. Congratulations.</p>
<h3 id="heading-updating-the-frontend-to-use-the-live-backend">Updating the Frontend to Use the Live Backend</h3>
<p>Open <code>app.js</code>.</p>
<p>Replace:</p>
<pre><code class="lang-bash">http://localhost:8000/remove-bg
</code></pre>
<p>With:</p>
<pre><code class="lang-bash">https://YOUR_CLOUD_RUN_URL/remove-bg
</code></pre>
<p>Save the file and reload the frontend.</p>
<h2 id="heading-step-5-making-the-backend-and-frontend-work-together"><strong>Step 5: Making the Backend and Frontend Work Together</strong></h2>
<p>At this point, we have two things:</p>
<ul>
<li><p>A backend running on the internet</p>
</li>
<li><p>A frontend running in the browser</p>
</li>
</ul>
<p>Now we want them to talk to each other.</p>
<p>Open your frontend, select an image, and click the button. You’ll notice that it still doesn’t work. This is expected.</p>
<h3 id="heading-what-is-happening-here">What Is Happening Here?</h3>
<p>Your frontend is running on one address, while your backend is running on another address.</p>
<p>Browsers are very strict about this. By default, a browser will block requests from one website to another unless the backend explicitly allows it. This is a security feature.</p>
<p>This rule is called <strong>CORS</strong>.</p>
<h3 id="heading-clearing-a-common-misconception-about-cors">Clearing a Common Misconception About CORS</h3>
<p>When beginners see a CORS error, they often think something is broken.</p>
<p>Nothing is broken. CORS is simply the browser saying: “I need the backend to confirm that this frontend is allowed to talk to it.”</p>
<p>So all we need to do is tell the backend: “It’s okay for requests to come from my frontend.”</p>
<h3 id="heading-allowing-only-our-frontend-not-everyone">Allowing Only Our Frontend (Not Everyone)</h3>
<p>Instead of allowing requests from everywhere, we’ll allow requests only from our frontend. This is a good habit to learn early.</p>
<p>Open <code>backend/api/main.py</code>.</p>
<p>Add this import at the top:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> fastapi.middleware.cors <span class="hljs-keyword">import</span> CORSMiddleware
</code></pre>
<p>Then, after creating the FastAPI app, add this:</p>
<pre><code class="lang-python">app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        <span class="hljs-string">"http://127.0.0.1:5500"</span>,
        <span class="hljs-string">"http://localhost:5500"</span>
    ],
    allow_methods=[<span class="hljs-string">"POST"</span>],
    allow_headers=[<span class="hljs-string">"*"</span>],
)
</code></pre>
<p>Why these URLs?</p>
<p>If you’re using the Live Server extension, your frontend is usually served on port <code>5500</code>. These are the addresses your browser is using locally.</p>
<p>We’re telling the backend: “Only accept requests from this frontend.”</p>
<p>That is exactly what we want.</p>
<h3 id="heading-redeploying-the-backend">Redeploying the Backend</h3>
<p>Any time you change backend code, you need to redeploy it.</p>
<p>Since our backend is deployed on Cloud Run and set up with automatic deploy, redeploying is simple, all you need to do is push your changes.</p>
<p>From the project root, run:</p>
<pre><code class="lang-go">git add .
git commit -m <span class="hljs-string">"Add CORS configuration"</span>
git push
</code></pre>
<p>Cloud Run will automatically detect the change and redeploy your backend.</p>
<p>Wait for the deployment to finish. Once it’s done, your backend will now allow requests from your local frontend.</p>
<h3 id="heading-testing-again">Testing Again</h3>
<p>Reload your frontend in the browser.</p>
<p>Select an image and click the button. This time, it should work.</p>
<p>You just handled a real browser security rule that every production app runs into. That alone is a huge learning step.</p>
<h2 id="heading-step-6-putting-the-frontend-on-the-internet-github-pages">Step 6: Putting the Frontend on the Internet (GitHub Pages)</h2>
<p>Right now, your frontend works only on your computer.</p>
<p>Just like the backend earlier, this means no one else can use it.</p>
<p>Let’s fix that.</p>
<h3 id="heading-why-github-pages">Why GitHub Pages?</h3>
<p>Our frontend is:</p>
<ul>
<li><p>Just HTML, CSS, and JavaScript</p>
</li>
<li><p>No backend code</p>
</li>
<li><p>No build step</p>
</li>
</ul>
<p>This makes it perfect for GitHub Pages. GitHub Pages can host static sites for free, and it’s very beginner friendly.</p>
<h3 id="heading-preparing-the-frontend-for-deployment">Preparing the Frontend for Deployment</h3>
<p>Make sure all your frontend files are inside the frontend folder:</p>
<pre><code class="lang-javascript">frontend/
  index.html
  styles.css
  app.js
</code></pre>
<p>Open app.js and make sure the backend URL is the Cloud Run URL, not localhost.</p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">"https://YOUR_CLOUD_RUN_URL/remove-bg"</span>, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
  <span class="hljs-attr">body</span>: formData,
});
</code></pre>
<p>Save the file.</p>
<h3 id="heading-pushing-the-frontend-to-github">Pushing the Frontend to GitHub</h3>
<p>We already created a GitHub repository earlier, so we’ll reuse it.</p>
<p>From the project root, run:</p>
<pre><code class="lang-javascript">git add .
git commit -m <span class="hljs-string">"Add frontend and prepare for GitHub Pages"</span>
git push
</code></pre>
<h3 id="heading-enabling-github-pages">Enabling GitHub Pages</h3>
<ol>
<li><p>Go to your repository on GitHub.</p>
</li>
<li><p>Open Settings.</p>
</li>
<li><p>Click Pages.</p>
</li>
</ol>
<p>Under Source, select:</p>
<ol>
<li><p>Branch: main</p>
</li>
<li><p>Folder: /(root)</p>
</li>
</ol>
<p>Save everything. After a few seconds, GitHub will give you a URL. This URL is now your frontend on the internet.</p>
<h3 id="heading-updating-cors-for-the-live-frontend">Updating CORS for the Live Frontend</h3>
<p>Now that the frontend is live, go back to backend/api/main.py.</p>
<p>Replace the local origins with your GitHub Pages URL:</p>
<pre><code class="lang-python">allow_origins=[
    <span class="hljs-string">"https://YOUR_GITHUB_USERNAME.github.io"</span>
]
</code></pre>
<p>Commit and push the change:</p>
<pre><code class="lang-bash">git add .
git commit -m <span class="hljs-string">"Update CORS for GitHub Pages"</span>
git push
</code></pre>
<p>Cloud Run will redeploy the backend automatically.</p>
<h3 id="heading-final-test">Final Test</h3>
<p>Open your GitHub Pages URL.</p>
<p>Upload an image, remove the background, and download the result.</p>
<p>Everything is now live.</p>
<h2 id="heading-where-you-are-now">Where You Are Now</h2>
<p>Let’s be very clear about what you just did.</p>
<p>You:</p>
<ul>
<li><p>Built a real backend</p>
</li>
<li><p>Deployed it to the internet</p>
</li>
<li><p>Built a frontend</p>
</li>
<li><p>Deployed it to the internet</p>
</li>
<li><p>Fixed real production issues</p>
</li>
<li><p>Connected everything properly</p>
</li>
</ul>
<p>This is not a demo project. This is a real application.</p>
<p>In the final section, we’ll wrap things up, talk about what you learned, and where you can go next.</p>
<h2 id="heading-final-thoughts-what-you-just-built-matters">Final Thoughts: What You Just Built Matters</h2>
<p>At this point, it is worth stopping and looking back at what you have actually done.</p>
<p>You didn’t just follow steps. You didn’t just copy code. You built a real application.</p>
<h3 id="heading-lets-be-clear-about-what-you-accomplished">Let’s Be Clear About What You Accomplished</h3>
<p>You started with nothing more than basic tools and ideas.</p>
<p>By the end of this tutorial, you:</p>
<ul>
<li><p>Built a backend that processes real data</p>
</li>
<li><p>Used a machine learning tool without fear or overthinking</p>
</li>
<li><p>Exposed a backend to the internet</p>
</li>
<li><p>Built a frontend with plain HTML, CSS, and JavaScript</p>
</li>
<li><p>Connected the frontend and backend properly</p>
</li>
<li><p>Deployed both parts so real users can access them</p>
</li>
</ul>
<p>This is exactly how real applications are built, just at a smaller and more manageable scale.</p>
<h3 id="heading-why-this-is-no-longer-a-beginner-project">Why This Is No Longer a “Beginner Project”</h3>
<p>Many projects are called beginner projects, but they stop at showing things on a screen.</p>
<p>This one does not.</p>
<p>Your app:</p>
<ul>
<li><p>Accepts real input</p>
</li>
<li><p>Performs real work</p>
</li>
<li><p>Runs on real servers</p>
</li>
<li><p>Handles real browser rules</p>
</li>
<li><p>Can be shared with anyone</p>
</li>
</ul>
<p>That is the difference between learning syntax and building software.</p>
<h3 id="heading-the-most-important-lesson-in-this-tutorial">The Most Important Lesson in This Tutorial</h3>
<p>The most important thing you should take away from this is not the project you built.</p>
<p>It is this: You didn’t need to “know more” before you started.</p>
<p>You learned by building. You figured things out as they appeared. You fixed problems when they showed up.</p>
<p>That is how experience is gained. No one has experience before building real applications. No one lacks experience after building many of them.</p>
<h3 id="heading-what-you-can-do-next">What You Can Do Next</h3>
<p>This project isn’t the end. It’s a starting point.</p>
<p>Here are a few ideas you can explore next, using what you already know:</p>
<ul>
<li><p>Improve the user interface</p>
</li>
<li><p>Add loading states and better feedback</p>
</li>
<li><p>Restrict image size or file types</p>
</li>
<li><p>Add simple rate limiting</p>
</li>
<li><p>Build another small tool that solves a real problem</p>
</li>
</ul>
<p>You don’t need to jump to frameworks yet.</p>
<p>If you can build a few more projects like this, frameworks will make a lot more sense when you meet them.</p>
<h3 id="heading-one-last-thought">One Last Thought</h3>
<p>If this was your first real project, you should be proud of yourself.</p>
<p>You moved past tutorials, built something useful, and put it on the internet. That’s the line many developers never cross.</p>
<p>Now that you have crossed it, the next one will be easier.</p>
<p>So keep building!</p>
<h3 id="heading-source-code-and-live-demo">Source Code and Live Demo</h3>
<p>If you want to explore the full project or build on top of it, you can find everything here.</p>
<ul>
<li><p>Live application: <a target="_blank" href="https://iamspruce.github.io/background-remover/">https://iamspruce.github.io/background-remover/</a></p>
</li>
<li><p>GitHub repository: <a target="_blank" href="https://github.com/iamspruce/background-remover">https://github.com/iamspruce/background-remover</a></p>
</li>
</ul>
<p>If you have questions, reach me on X at <a target="_blank" href="https://x.com/sprucekhalifa"><code>@sprucekhalifa</code></a>. I write practical tech articles like this regularly.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Turn Your Favorite Tech Blogs into a Personal Podcast ]]>
                </title>
                <description>
                    <![CDATA[ These days it feels almost impossible to keep up with tech news. I step away for three days, and suddenly there is a new AI model, a new framework, and a new tool everyone says I must learn. Reading everything no longer scales, but I still want to st... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-turn-your-favorite-blogs-into-personal-podcast/</link>
                <guid isPermaLink="false">6971493162f064cd7502688f</guid>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Wed, 21 Jan 2026 21:46:25 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769029504274/8900a8bf-73cd-4944-b0d6-e440efd1bc96.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>These days it feels almost impossible to keep up with tech news. I step away for three days, and suddenly there is a new AI model, a new framework, and a new tool everyone says I must learn. Reading everything no longer scales, but I still want to stay informed.</p>
<p>So I decided to change the format instead of giving up. I took a few tech blogs I already enjoy reading, picked the best articles, converted them to audio using my own voice, and turned the result into a private podcast. Now I can stay up to date while walking, running, or driving.</p>
<p>In this tutorial, you’ll learn how to build a simplified version of that pipeline step by step.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-you-are-going-to-build">What You Are Going to Build</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-project-overview">Project Overview</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-getting-started">Getting Started</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-get-the-content">How to Get the Content</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-filter-the-content">How to Filter the Content</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-clean-up-the-content">How to Clean Up the Content</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-convert-content-to-audio">How to Convert Content to Audio</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-upload-the-audio-to-cloudflare-r2">How to Upload the Audio to Cloudflare R2</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-make-the-podcast">How to Make the Podcast</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-automate-the-pipeline">How to Automate the Pipeline</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-you-are-going-to-build"><strong>What You Are Going to Build</strong></h2>
<p>You will build a Node.js script that does the following:</p>
<ul>
<li><p>Fetches articles from RSS feeds.</p>
</li>
<li><p>Extracts clean, readable text from each article.</p>
</li>
<li><p>Filters out content you do not want to listen to.</p>
</li>
<li><p>Cleans the text so it sounds good when spoken.</p>
</li>
<li><p>Converts the text to natural-sounding audio using your own voice.</p>
</li>
<li><p>Uploads the audio to Cloudflare R2.</p>
</li>
<li><p>Generates a podcast RSS feed.</p>
</li>
<li><p>Runs automatically on a schedule.</p>
</li>
</ul>
<p>At the end, you will have a real podcast feed you can subscribe to on your phone.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768711883596/a35c2a6b-6f9f-4f3d-898f-0f9bff798e6e.png" alt="The generated podcast showing converted blog posts as episodes." class="image--center mx-auto" width="1536" height="1024" loading="lazy"></p>
<p>If you want to skip the tutorial and jump straight into using the finished tool, you can find the complete version and instructions on <a target="_blank" href="https://github.com/iamspruce/postcast">Gi</a>tHub.</p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>To follow along, you need basic JavaScript knowledge.</p>
<p>You also need:</p>
<ul>
<li><p>Node.js 22 or newer.</p>
</li>
<li><p>A place to store audio files (<a target="_blank" href="https://dash.cloudflare.com/">Cloudflare</a> R2 in this tutorial).</p>
</li>
<li><p>A text-to-speech API (<a target="_blank" href="http://orangeclone.com">OrangeClone</a> in this tutorial).</p>
</li>
</ul>
<h2 id="heading-project-overview"><strong>Project Overview</strong></h2>
<p>Before writing code, it helps to understand the idea clearly.</p>
<p>This project is a pipeline:</p>
<pre><code class="lang-text">Fetch content -&gt; Filter content -&gt; Clean up content -&gt; Convert to audio -&gt; Repeat
</code></pre>
<p>Each step takes the output of the previous one. Keeping the flow linear makes the project easier to reason about, debug, and automate.</p>
<p>All code in this tutorial lives in a single file called <code>index.js</code>.</p>
<h2 id="heading-getting-started"><strong>Getting Started</strong></h2>
<p>Create a new project folder and your main file.</p>
<pre><code class="lang-bash">mkdir podcast-pipeline
<span class="hljs-built_in">cd</span> podcast-pipeline
touch index.js
</code></pre>
<p>Initialize the project and install dependencies.</p>
<pre><code class="lang-bash">npm init -y
npm install rss-parser @mozilla/readability jsdom node-fetch uuid xmlbuilder @aws-sdk/client-s3
</code></pre>
<p>Enable ESM so <code>import</code> syntax works in Node 22.</p>
<pre><code class="lang-bash">npm pkg <span class="hljs-built_in">set</span> <span class="hljs-built_in">type</span>=module
</code></pre>
<p>Here is what each dependency is used for:</p>
<ul>
<li><p><code>rss-parser</code> reads RSS feeds.</p>
</li>
<li><p><code>@mozilla/readability</code> extracts readable article text.</p>
</li>
<li><p><code>jsdom</code> provides a DOM for Readability.</p>
</li>
<li><p><code>node-fetch</code> fetches remote content.</p>
</li>
<li><p><code>uuid</code> generates unique filenames.</p>
</li>
<li><p><code>xmlbuilder</code> creates the podcast RSS feed.</p>
</li>
<li><p><code>@aws-sdk/client-s3</code> uploads audio to Cloudflare R2.</p>
</li>
</ul>
<h2 id="heading-how-to-get-the-content"><strong>How to Get the Content</strong></h2>
<p>The first decision is where your content comes from.</p>
<p>Avoid scraping websites directly. Scraped HTML is noisy and inconsistent. RSS feeds are structured and reliable. Most serious blogs provide one.</p>
<p>Open <code>index.js</code> and define your sources.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Parser <span class="hljs-keyword">from</span> <span class="hljs-string">"rss-parser"</span>;
<span class="hljs-keyword">import</span> fetch <span class="hljs-keyword">from</span> <span class="hljs-string">"node-fetch"</span>;
<span class="hljs-keyword">import</span> { JSDOM } <span class="hljs-keyword">from</span> <span class="hljs-string">"jsdom"</span>;
<span class="hljs-keyword">import</span> { Readability } <span class="hljs-keyword">from</span> <span class="hljs-string">"@mozilla/readability"</span>;

<span class="hljs-keyword">const</span> parser = <span class="hljs-keyword">new</span> Parser();

<span class="hljs-keyword">const</span> NUMBER_OF_ARTICLES_TO_FETCH = <span class="hljs-number">15</span>;

<span class="hljs-keyword">const</span> SOURCES = [
  <span class="hljs-string">"https://www.freecodecamp.org/news/rss/"</span>,
  <span class="hljs-string">"https://hnrss.org/frontpage"</span>,
];
</code></pre>
<p>Now fetch articles and extract readable content.</p>
<pre><code class="lang-js"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fetchArticles</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> articles = [];

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> source <span class="hljs-keyword">of</span> SOURCES) {
    <span class="hljs-keyword">const</span> feed = <span class="hljs-keyword">await</span> parser.parseURL(source);

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> item <span class="hljs-keyword">of</span> feed.items.slice(<span class="hljs-number">0</span>, NUMBER_OF_ARTICLES_TO_FETCH)) {
      <span class="hljs-keyword">if</span> (!item.link) <span class="hljs-keyword">continue</span>;

      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(item.link);
      <span class="hljs-keyword">const</span> html = <span class="hljs-keyword">await</span> response.text();

      <span class="hljs-keyword">const</span> dom = <span class="hljs-keyword">new</span> JSDOM(html, { <span class="hljs-attr">url</span>: item.link });
      <span class="hljs-keyword">const</span> reader = <span class="hljs-keyword">new</span> Readability(dom.window.document);
      <span class="hljs-keyword">const</span> content = reader.parse();

      <span class="hljs-keyword">if</span> (!content) <span class="hljs-keyword">continue</span>;

      articles.push({
        <span class="hljs-attr">title</span>: item.title,
        <span class="hljs-attr">link</span>: item.link,
        <span class="hljs-attr">content</span>: content.content,
        <span class="hljs-attr">text</span>: content.textContent,
      });
    }
  }

  <span class="hljs-keyword">return</span> articles.slice(<span class="hljs-number">0</span>, NUMBER_OF_ARTICLES_TO_FETCH);
}
</code></pre>
<p>This function:</p>
<ul>
<li><p>Reads RSS feeds.</p>
</li>
<li><p>Downloads each article.</p>
</li>
<li><p>Extracts clean text using Readability.</p>
</li>
<li><p>Returns a list of articles ready for processing.</p>
</li>
</ul>
<h2 id="heading-how-to-filter-the-content"><strong>How to Filter the Content</strong></h2>
<p>Not every article deserves your attention. Start by filtering out topics you do not want to hear about.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> BLOCKED_KEYWORDS = [<span class="hljs-string">"crypto"</span>, <span class="hljs-string">"nft"</span>, <span class="hljs-string">"giveaway"</span>];

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">filterByKeywords</span>(<span class="hljs-params">articles</span>) </span>{
  <span class="hljs-keyword">return</span> articles.filter(
    <span class="hljs-function">(<span class="hljs-params">article</span>) =&gt;</span>
      !BLOCKED_KEYWORDS.some(<span class="hljs-function">(<span class="hljs-params">keyword</span>) =&gt;</span>
        article.text.toLowerCase().includes(keyword)
      )
  );
}
</code></pre>
<p>Next, remove promotional content.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">removePromotionalContent</span>(<span class="hljs-params">articles</span>) </span>{
  <span class="hljs-keyword">return</span> articles.filter(
    <span class="hljs-function">(<span class="hljs-params">article</span>) =&gt;</span> !article.text.toLowerCase().includes(<span class="hljs-string">"sponsored"</span>)
  );
}
</code></pre>
<p>Finally, remove articles that are too short.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">filterByWordCount</span>(<span class="hljs-params">articles, minWords = <span class="hljs-number">700</span></span>) </span>{
  <span class="hljs-keyword">return</span> articles.filter(
    <span class="hljs-function">(<span class="hljs-params">article</span>) =&gt;</span> article.text.split(<span class="hljs-regexp">/\s+/</span>).length &gt;= minWords
  );
}
</code></pre>
<p>After these steps, you are left with articles you actually want to listen to.</p>
<h2 id="heading-how-to-clean-up-the-content"><strong>How to Clean Up the Content</strong></h2>
<p>Raw articles text still need to be cleaned up to sound good when spoken. First, replace images with spoken placeholders.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">replaceImages</span>(<span class="hljs-params">html</span>) </span>{
  <span class="hljs-keyword">return</span> html.replace(<span class="hljs-regexp">/&lt;img[^&gt;]*alt="([^"]*)"[^&gt;]*&gt;/gi</span>, <span class="hljs-function">(<span class="hljs-params">_, alt</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> alt ? <span class="hljs-string">`[Image: <span class="hljs-subst">${alt}</span>]`</span> : <span class="hljs-string">`[Image omitted]`</span>;
  });
}
</code></pre>
<p>Next, remove code blocks.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">replaceCodeBlocks</span>(<span class="hljs-params">html</span>) </span>{
  <span class="hljs-keyword">return</span> html.replace(
    <span class="hljs-regexp">/&lt;pre&gt;&lt;code&gt;[\s\S]*?&lt;\/code&gt;&lt;\/pre&gt;/gi</span>,
    <span class="hljs-string">"[Code example omitted]"</span>
  );
}
</code></pre>
<p>Strip URLs and replace them with spoken text.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">replaceUrls</span>(<span class="hljs-params">text</span>) </span>{
  <span class="hljs-keyword">return</span> text.replace(<span class="hljs-regexp">/https?:\/\/\S+/gi</span>, <span class="hljs-string">"link removed"</span>);
}
</code></pre>
<p>Normalize common symbols.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">normalizeSymbols</span>(<span class="hljs-params">text</span>) </span>{
  <span class="hljs-keyword">return</span> text
    .replace(<span class="hljs-regexp">/&amp;/g</span>, <span class="hljs-string">"and"</span>)
    .replace(<span class="hljs-regexp">/%/g</span>, <span class="hljs-string">"percent"</span>)
    .replace(<span class="hljs-regexp">/\$/g</span>, <span class="hljs-string">"dollar"</span>);
}
</code></pre>
<p>Convert HTML to text so TTS does not read tags.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">stripHtml</span>(<span class="hljs-params">html</span>) </span>{
  <span class="hljs-keyword">return</span> html.replace(<span class="hljs-regexp">/&lt;[^&gt;]+&gt;/g</span>, <span class="hljs-string">" "</span>);
}
</code></pre>
<p>Combine everything into one cleanup step.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">cleanArticle</span>(<span class="hljs-params">article</span>) </span>{
  <span class="hljs-keyword">let</span> cleaned = replaceImages(article.content);
  cleaned = replaceCodeBlocks(cleaned);
  cleaned = stripHtml(cleaned);
  cleaned = replaceUrls(cleaned);
  cleaned = normalizeSymbols(cleaned);

  <span class="hljs-keyword">return</span> {
    ...article,
    <span class="hljs-attr">cleanedText</span>: cleaned,
  };
}
</code></pre>
<p>At this point, the text is ready for audio generation.</p>
<h2 id="heading-how-to-convert-content-to-audio"><strong>How to Convert Content to Audio</strong></h2>
<p>Browser speech APIs sound robotic. I wanted something that sounded human and familiar. After trying several tools, I settled on OrangeClone. It was the only option that actually sounded like me.</p>
<p>Create a free account and copy your API key from the dashboard.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768712061376/cd437cea-8957-4cb6-98c8-b5f6e520b57b.png" alt="OrangeClone dashboard with API key visible." class="image--center mx-auto" width="2624" height="1822" loading="lazy"></p>
<p>Record 10 to 15 seconds of clean audio and save it as <code>SAMPLE_VOICE.wav</code> in the project root. Then create a voice character (one-time setup).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"node:fs/promises"</span>;

<span class="hljs-keyword">const</span> ORANGECLONE_API_KEY = process.env.ORANGECLONE_API_KEY;
<span class="hljs-keyword">const</span> ORANGECLONE_BASE_URL =
  process.env.ORANGECLONE_BASE_URL || <span class="hljs-string">"https://orangeclone.com/api"</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createVoiceCharacter</span>(<span class="hljs-params">{ name, avatarStyle, voiceSamplePath }</span>) </span>{
  <span class="hljs-keyword">const</span> audioBuffer = <span class="hljs-keyword">await</span> fs.readFile(voiceSamplePath);
  <span class="hljs-keyword">const</span> audioBase64 = audioBuffer.toString(<span class="hljs-string">"base64"</span>);

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
    <span class="hljs-string">`<span class="hljs-subst">${ORANGECLONE_BASE_URL}</span>/characters/create`</span>,
    {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${ORANGECLONE_API_KEY}</span>`</span>,
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        name,
        avatarStyle,
        <span class="hljs-attr">voiceSample</span>: {
          <span class="hljs-attr">format</span>: <span class="hljs-string">"wav"</span>,
          <span class="hljs-attr">data</span>: audioBase64,
        },
      }),
    }
  );

  <span class="hljs-keyword">if</span> (!response.ok) {
    <span class="hljs-keyword">const</span> errorText = <span class="hljs-keyword">await</span> response.text();
    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Failed to create character: <span class="hljs-subst">${errorText}</span>`</span>);
  }

  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();

  <span class="hljs-keyword">return</span> (
    data.data?.id ||
    data.data?.characterId ||
    data.id ||
    data.characterId
  );
}
</code></pre>
<p>Generate audio from text.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generateAudio</span>(<span class="hljs-params">characterId, text</span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`<span class="hljs-subst">${ORANGECLONE_BASE_URL}</span>/voices_clone`</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${ORANGECLONE_API_KEY}</span>`</span>,
      <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
    },
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
      characterId,
      text,
    }),
  });

  <span class="hljs-keyword">return</span> response.json();
}
</code></pre>
<p>Wait for the job to complete.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">waitForAudio</span>(<span class="hljs-params">jobId</span>) </span>{
  <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`<span class="hljs-subst">${ORANGECLONE_BASE_URL}</span>/voices/<span class="hljs-subst">${jobId}</span>`</span>);
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();

    <span class="hljs-keyword">if</span> (data.status === <span class="hljs-string">"completed"</span>) {
      <span class="hljs-keyword">return</span> data.audioUrl;
    }

    <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">r</span>) =&gt;</span> <span class="hljs-built_in">setTimeout</span>(r, <span class="hljs-number">5000</span>));
  }
}
</code></pre>
<h2 id="heading-how-to-upload-the-audio-to-cloudflare-r2">How to Upload the Audio to Cloudflare R2</h2>
<p>OrangeClone returns an audio URL, but podcast apps need a stable, public file that will not expire.<br>That is where Cloudflare R2 comes in.</p>
<p>R2 is S3-compatible storage, which means we can upload files using the AWS SDK and serve them publicly for podcast apps.</p>
<h2 id="heading-how-to-set-up-credentials">How to Set Up Credentials</h2>
<p>Create an R2 bucket in your Cloudflare dashboard and set the following environment variables:</p>
<ul>
<li><p><code>R2_ACCOUNT_ID</code></p>
</li>
<li><p><code>R2_ACCESS_KEY_ID</code></p>
</li>
<li><p><code>R2_SECRET_ACCESS_KEY</code></p>
</li>
<li><p><code>R2_BUCKET_NAME</code></p>
</li>
<li><p><code>R2_PUBLIC_URL</code></p>
</li>
</ul>
<p>These values allow the script to upload files and generate public URLs for them.</p>
<h2 id="heading-how-to-initialize-the-r2-client">How to Initialize the R2 Client</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { S3Client, PutObjectCommand } <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-s3"</span>;

<span class="hljs-keyword">const</span> r2 = <span class="hljs-keyword">new</span> S3Client({
  <span class="hljs-attr">region</span>: <span class="hljs-string">"auto"</span>,
  <span class="hljs-attr">endpoint</span>: <span class="hljs-string">`https://<span class="hljs-subst">${process.env.R2_ACCOUNT_ID}</span>.r2.cloudflarestorage.com`</span>,
  <span class="hljs-attr">credentials</span>: {
    <span class="hljs-attr">accessKeyId</span>: process.env.R2_ACCESS_KEY_ID,
    <span class="hljs-attr">secretAccessKey</span>: process.env.R2_SECRET_ACCESS_KEY,
  },
});
</code></pre>
<p>This creates an S3-compatible client that connects directly to your Cloudflare R2 account instead of AWS.</p>
<h2 id="heading-how-to-download-the-audio">How to Download the Audio</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">downloadAudio</span>(<span class="hljs-params">audioUrl</span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(audioUrl);
  <span class="hljs-keyword">const</span> buffer = <span class="hljs-keyword">await</span> response.arrayBuffer();
  <span class="hljs-keyword">return</span> Buffer.from(buffer);
}
</code></pre>
<p>OrangeClone gives us a URL, not a file.<br>This function downloads the audio and converts it into a Node.js buffer so it can be uploaded to R2.</p>
<h2 id="heading-how-to-upload-to-r2">How to Upload to R2</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { v4 <span class="hljs-keyword">as</span> uuid } <span class="hljs-keyword">from</span> <span class="hljs-string">"uuid"</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">uploadToR2</span>(<span class="hljs-params">audioBuffer</span>) </span>{
  <span class="hljs-keyword">const</span> fileName = <span class="hljs-string">`<span class="hljs-subst">${uuid()}</span>.mp3`</span>;

  <span class="hljs-keyword">const</span> command = <span class="hljs-keyword">new</span> PutObjectCommand({
    <span class="hljs-attr">Bucket</span>: process.env.R2_BUCKET_NAME,
    <span class="hljs-attr">Key</span>: fileName,
    <span class="hljs-attr">Body</span>: audioBuffer,
    <span class="hljs-attr">ContentType</span>: <span class="hljs-string">"audio/mpeg"</span>,
  });

  <span class="hljs-keyword">await</span> r2.send(command);

  <span class="hljs-keyword">return</span> <span class="hljs-string">`<span class="hljs-subst">${process.env.R2_PUBLIC_URL}</span>/<span class="hljs-subst">${fileName}</span>`</span>;
}
</code></pre>
<p>This function uploads the audio buffer to R2 using a unique filename and returns a public URL that podcast apps can access.</p>
<h2 id="heading-putting-it-together">Putting It Together</h2>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> audioUrl = <span class="hljs-keyword">await</span> waitForAudio(jobId);
<span class="hljs-keyword">const</span> audioBuffer = <span class="hljs-keyword">await</span> downloadAudio(audioUrl);
<span class="hljs-keyword">const</span> publicAudioUrl = <span class="hljs-keyword">await</span> uploadToR2(audioBuffer);
</code></pre>
<p>At the end of this step, <code>publicAudioUrl</code> is the final audio file used in the podcast RSS feed.</p>
<h2 id="heading-how-to-make-the-podcast"><strong>How to Make the Podcast</strong></h2>
<p>With public audio URLs, you can now generate an RSS feed.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> xmlbuilder <span class="hljs-keyword">from</span> <span class="hljs-string">"xmlbuilder"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">generatePodcastFeed</span>(<span class="hljs-params">episodes</span>) </span>{
  <span class="hljs-keyword">const</span> feed = xmlbuilder
    .create(<span class="hljs-string">"rss"</span>, { <span class="hljs-attr">version</span>: <span class="hljs-string">"1.0"</span> })
    .att(<span class="hljs-string">"version"</span>, <span class="hljs-string">"2.0"</span>)
    .ele(<span class="hljs-string">"channel"</span>);

  feed.ele(<span class="hljs-string">"title"</span>, <span class="hljs-string">"My Tech Podcast"</span>);
  feed.ele(<span class="hljs-string">"description"</span>, <span class="hljs-string">"Tech articles converted to audio"</span>);
  feed.ele(<span class="hljs-string">"link"</span>, <span class="hljs-string">"https://your-site.com"</span>);

  episodes.forEach(<span class="hljs-function">(<span class="hljs-params">ep</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> item = feed.ele(<span class="hljs-string">"item"</span>);
    item.ele(<span class="hljs-string">"title"</span>, ep.title);
    item.ele(<span class="hljs-string">"enclosure"</span>, {
      <span class="hljs-attr">url</span>: ep.audioUrl,
      <span class="hljs-attr">type</span>: <span class="hljs-string">"audio/mpeg"</span>,
    });
  });

  <span class="hljs-keyword">return</span> feed.end({ <span class="hljs-attr">pretty</span>: <span class="hljs-literal">true</span> });
}
</code></pre>
<h2 id="heading-how-to-automate-the-pipeline"><strong>How to Automate the Pipeline</strong></h2>
<p>Automation in this project happens in two stages. First, the code itself must be able to process multiple articles in one run. Second, the script must run automatically on a schedule. We’ll start with the code-level automation.</p>
<h3 id="heading-automating-inside-the-code"><strong>Automating Inside the Code</strong></h3>
<p>Earlier, we fetched up to fifteen articles. Now we need to make sure every article that passes our filters goes through the full pipeline.</p>
<p>Add the following function near the bottom of <code>index.js</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">runPipeline</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> rawArticles = <span class="hljs-keyword">await</span> fetchArticles();

  <span class="hljs-keyword">const</span> filteredArticles = filterByWordCount(
    removePromotionalContent(filterByKeywords(rawArticles))
  );

  <span class="hljs-keyword">if</span> (filteredArticles.length === <span class="hljs-number">0</span>) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"No articles passed the filters"</span>);
    <span class="hljs-keyword">return</span> [];
  }

  <span class="hljs-keyword">const</span> characterId = <span class="hljs-keyword">await</span> createVoiceCharacter({
    <span class="hljs-attr">name</span>: <span class="hljs-string">"My Voice"</span>,
    <span class="hljs-attr">avatarStyle</span>: <span class="hljs-string">"realistic"</span>,
    <span class="hljs-attr">voiceSamplePath</span>: <span class="hljs-string">"./SAMPLE_VOICE.wav"</span>,
  });

  <span class="hljs-keyword">const</span> episodes = [];

  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> article <span class="hljs-keyword">of</span> filteredArticles) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Processing: <span class="hljs-subst">${article.title}</span>`</span>);

    <span class="hljs-keyword">const</span> cleaned = cleanArticle(article);

    <span class="hljs-keyword">const</span> job = <span class="hljs-keyword">await</span> generateAudio(characterId, cleaned.cleanedText);

    <span class="hljs-keyword">const</span> audioUrl = <span class="hljs-keyword">await</span> waitForAudio(job.id);
    <span class="hljs-keyword">const</span> audioBuffer = <span class="hljs-keyword">await</span> downloadAudio(audioUrl);
    <span class="hljs-keyword">const</span> publicAudioUrl = <span class="hljs-keyword">await</span> uploadToR2(audioBuffer);

    episodes.push({
      <span class="hljs-attr">title</span>: article.title,
      <span class="hljs-attr">audioUrl</span>: publicAudioUrl,
    });
  }

  <span class="hljs-keyword">return</span> episodes;
}
</code></pre>
<p>This function does all the heavy lifting:</p>
<ul>
<li><p>Fetches articles</p>
</li>
<li><p>Applies all filters</p>
</li>
<li><p>Creates the voice character once</p>
</li>
<li><p>Loops through every valid article</p>
</li>
<li><p>Converts each article into audio</p>
</li>
<li><p>Uploads the audio to Cloudflare R2</p>
</li>
<li><p>Collects podcast episode data</p>
</li>
</ul>
<p>At this point, one script run can generate multiple podcast episodes.</p>
<h3 id="heading-running-the-pipeline-and-generating-the-feed"><strong>Running the Pipeline and Generating the Feed</strong></h3>
<p>Now we need a single entry point that runs the pipeline and writes the podcast feed. Add this below the pipeline function.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> fs <span class="hljs-keyword">from</span> <span class="hljs-string">"node:fs/promises"</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> episodes = <span class="hljs-keyword">await</span> runPipeline();

  <span class="hljs-keyword">if</span> (episodes.length === <span class="hljs-number">0</span>) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"No episodes generated"</span>);
    <span class="hljs-keyword">return</span>;
  }

  <span class="hljs-keyword">const</span> rss = generatePodcastFeed(episodes);

  <span class="hljs-keyword">await</span> fs.mkdir(<span class="hljs-string">"./public"</span>, { <span class="hljs-attr">recursive</span>: <span class="hljs-literal">true</span> });
  <span class="hljs-keyword">await</span> fs.writeFile(<span class="hljs-string">"./public/feed.xml"</span>, rss);

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Podcast feed generated at public/feed.xml"</span>);
}

main().catch(<span class="hljs-built_in">console</span>.error);
</code></pre>
<p>When you run <code>node index.js</code>, this now:</p>
<ul>
<li><p>Processes all selected articles</p>
</li>
<li><p>Creates multiple audio files</p>
</li>
<li><p>Generates a valid podcast RSS feed</p>
</li>
</ul>
<p>This is the core automation.</p>
<h3 id="heading-scheduling-the-pipeline-with-github-actions"><strong>Scheduling the Pipeline with GitHub Actions</strong></h3>
<p>The final step is to make this script run automatically. Create a GitHub Actions workflow file at <code>.github/workflows/podcast.yml</code>.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Podcast</span> <span class="hljs-string">Pipeline</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">schedule:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">cron:</span> <span class="hljs-string">"0 6 * * *"</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">run:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v4</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">node-version:</span> <span class="hljs-number">22</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">run:</span> <span class="hljs-string">node</span> <span class="hljs-string">index.js</span>
        <span class="hljs-attr">env:</span>
          <span class="hljs-attr">ORANGECLONE_API_KEY:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.ORANGECLONE_API_KEY</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">R2_ACCOUNT_ID:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.R2_ACCOUNT_ID</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">R2_ACCESS_KEY_ID:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.R2_ACCESS_KEY_ID</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">R2_SECRET_ACCESS_KEY:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.R2_SECRET_ACCESS_KEY</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">R2_BUCKET_NAME:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.R2_BUCKET_NAME</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">R2_PUBLIC_URL:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.R2_PUBLIC_URL</span> <span class="hljs-string">}}</span>
</code></pre>
<p>This workflow runs the pipeline every morning at 6 AM.</p>
<p>Each run:</p>
<ul>
<li><p>Fetches new articles</p>
</li>
<li><p>Generates fresh audio</p>
</li>
<li><p>Updates the podcast feed</p>
</li>
</ul>
<p>Once this is set up, your podcast updates itself without manual work.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>This is a basic version of my full production pipeline, <a target="_blank" href="https://github.com/iamspruce/postcast">PostCast</a>, but the core idea is the same.</p>
<p>You now know how to turn blogs into a personal podcast. Be mindful of copyright and only use content you are allowed to consume.</p>
<p>If you have questions, reach me on X at <code>@</code><a target="_blank" href="https://x.com/sprucekhalifa"><code>sprucekhalifa</code></a>. I write practical tech articles like this regularly.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use AI Effectively in Your Dev Projects ]]>
                </title>
                <description>
                    <![CDATA[ “AI is not going to take your job – but a developer who knows how to use AI will.” I’ve seen this statement everywhere, and it’s the only one about AI taking our jobs that I totally agree with. Software development has changed. It’s not what it used ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-ai-effectively-in-your-dev-projects/</link>
                <guid isPermaLink="false">688151d98401037e348f65cd</guid>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ jobs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Wed, 23 Jul 2025 21:19:21 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753305511556/b5973363-1964-4abf-a29b-cf60668b33da.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong>“AI is not going to take your job – but a developer who knows how to use AI will.”</strong> I’ve seen this statement everywhere, and it’s the only one about AI taking our jobs that I totally agree with. Software development has changed. It’s not what it used to be, and that's a good thing.</p>
<p>Let's get one thing straight: AI is here to help, not to replace. Your job, my job, was never <em>just</em> to write code. Writing code was always just a part of it. Our real job is to build software solutions that work. And since an AI, trained on the collective knowledge of millions of developers, can probably write better, cleaner boilerplate than you, you should let it. Your expertise is better used elsewhere.</p>
<p>In this article, I’ll show you exactly how I use AI to get work done faster. We'll walk through building a car rental website, and you'll see how I use AI for:</p>
<ul>
<li><p>Initial planning and research</p>
</li>
<li><p>Design and even UI Copy</p>
</li>
<li><p>Writing all the boring boilerplate code</p>
</li>
<li><p>Improving the code and making it better</p>
</li>
</ul>
<p>Here’s what the website we're building looks like: (<a target="_blank" href="https://car-rental-tutorial.vercel.app">Live demo</a>) (<a target="_blank" href="https://github.com/iamspruce/car-rental-tutorial">Github Repo</a>)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753118807037/0802b468-c69d-4792-9ac9-6ebe0421eef5.png" alt="Final design of a responsive car rental website" class="image--center mx-auto" width="2742" height="1842" loading="lazy"></p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-step-1-planning-and-research-the-brainstorm">Step 1: Planning and Research (The Brainstorm)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-design-and-ui-copy">Step 2: Design and UI Copy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-writing-the-boilerplate-code">Step 3: Writing the Boilerplate Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-making-the-code-actually-good">Step 4: Making the Code Actually Good</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-the-ai-got-write-and-wrong">What the AI Got Right (and Wrong)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-refactoring-in-action">Refactoring in Action</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-so-whats-the-takeaway">So, What's the Takeaway?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-frequently-asked-questions">Frequently Asked Questions</a></p>
</li>
</ol>
<h2 id="heading-step-1-planning-and-research-the-brainstorm">Step 1: Planning and Research (The Brainstorm)</h2>
<p>So, a client hits me up. They own a car rental business and want a simple website. People need to see the cars and have an easy way to call and rent them. Simple enough.</p>
<p>So what do I do? I don't fire up VS Code. I take this info straight to ChatGPT and ask it for ideas.</p>
<p><strong>Prompt:</strong></p>
<blockquote>
<p>You’re a website designer and you have a client that owns a car rental website. They want a simple website that displays the cars they have for rent and an option for people to rent them. How would you go about building this?</p>
</blockquote>
<p>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753119862498/a583a845-73d7-41e3-be32-c880702e6d90.png" alt="ChatGPT output showing a proposed plan for building a car rental website, including key features and suggested tech stack." class="image--center mx-auto" width="1600" height="400" loading="lazy"></p>
<p>You can see how easy that was. So what did it spit out? Basically a full project brief. It gave me a roadmap suggesting key pages like a Homepage, Car Listings, and a Contact page. It also outlined essential features like a search bar and filtering options, and recommended a modern tech stack like React which was exactly what I was planning to use.</p>
<p>With that sorted, I wanted to see what it might look like, so I had it generate some quick wireframes.</p>
<p><strong>Prompt:</strong></p>
<blockquote>
<p>From the above, Generate the wireframes of what the entire website with its pages will look like.</p>
</blockquote>
<p>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753115541678/26056ae5-ff2e-47de-af4a-2b34605d8802.png" alt="Basic wireframes generated by ChatGPT representing the layout of a car rental website, including homepage, car listings, and contact section." class="image--center mx-auto" width="2742" height="1842" loading="lazy"></p>
<p>Now I've got a blueprint. The whole discovery phase, which could take hours or days of back-and-forth, is done in minutes.</p>
<h2 id="heading-step-2-design-and-ui-copy">Step 2: Design and UI Copy</h2>
<p>Okay, I've got a rough idea of the layout. Time to turn these ugly wireframes into a real design. For this, I use AI-powered UI generation tools (you can find a few out there, like <a target="_blank" href="https://stitch.withgoogle.com/projects/17333997864138596143">https://stitch.withgoogle.com</a>, or even use <a target="_blank" href="https://v0.dev">v0.dev</a> to get ideas).</p>
<p>I just uploaded the wireframes from ChatGPT and told it what I wanted.</p>
<p><strong>Prompt:</strong></p>
<blockquote>
<p>Turn these wireframes into a clean, modern design for a car rental website. Make it look trustworthy.</p>
</blockquote>
<p>Output:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753114569826/ef5bbf7d-d62d-4237-b424-97b02873c07f.png" alt="AI-generated modern UI design for a car rental website, showcasing a clean, professional interface with car listings." class="image--center mx-auto" width="2742" height="1842" loading="lazy"></p>
<p>Now, one thing I love about these tools is that they don't just spit out a pretty picture. They give you the actual code for it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753114611241/a929850d-5d93-4338-a5f6-5dc7991118b7.png" alt="Code snippet provided by an AI UI tool that converts design directly into HTML and CSS for a car rental site." class="image--center mx-auto" width="2742" height="1842" loading="lazy"></p>
<p>Here’s a sample of the kind of clean HTML it gave me for a single car card:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md p-4 flex flex-col"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/path-to-your-car-image.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Toyota Camry"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"rounded-md mb-4"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h3</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-xl font-bold text-gray-800"</span>&gt;</span>Toyota Camry<span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-lg font-semibold text-blue-600 mt-2"</span>&gt;</span>$50/day<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-4 space-y-2 text-sm text-gray-600"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex items-center"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>4 Seats<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex items-center"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Automatic<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mt-auto bg-blue-500 text-white font-bold py-2 px-4 rounded-lg hover:bg-blue-600 transition duration-300"</span>&gt;</span>
    Rent Now
  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>You can always play with the full code <a target="_blank" href="https://github.com/iamspruce/car-rental-tutorial">here</a>.</p>
<p>And just like that, I've got the design of the website and the starter code for it. No Figma, no slicing assets, just straight from an idea to code.</p>
<h2 id="heading-step-3-writing-the-boilerplate-code">Step 3: Writing the Boilerplate Code</h2>
<p>I said earlier that AI can write better code than you, and I stand by it. It was trained on all the code from every public repo, every tutorial, every developer put together. Assuming the collective brain of every developer is better than you alone, the AI has a serious edge – <em>if</em> you can guide it.</p>
<p>For my car rental site, I wanted to use React. So I just copied the HTML code from the design tool and pasted it into Gemini with some very clear instructions.</p>
<p><strong>Prompt:</strong></p>
<blockquote>
<p>You are a senior React developer. Convert the following HTML and Tailwind CSS code into a fully functional React application.</p>
<p><strong>Requirements:</strong></p>
<ol>
<li><p>Use Vite as the build tool.</p>
</li>
<li><p>The project must be in TypeScript.</p>
</li>
<li><p>Implement the UI components using <code>shadcn/ui</code> where appropriate (for example, Buttons, Cards).</p>
</li>
<li><p>Use lucide-react for icons</p>
</li>
<li><p>Structure the code into logical components (for example, <code>Navbar</code>, <code>CarCard</code>, <code>Footer</code>).</p>
</li>
<li><p>Create a root <code>App.tsx</code> file that assembles these components.Output:</p>
</li>
</ol>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1753115245332/b1a0f42c-820c-4f7e-9730-77fb47cc35fb.png" alt="Gemini output converting HTML and Tailwind code into a functional React + TypeScript app using shadcn/ui and lucide-react." class="image--center mx-auto" width="2742" height="1842" loading="lazy"></p>
<p>Notice how I was super specific about the tools I wanted? If you want the best output, you have to tell the AI exactly what you want. Don't be vague. Guide it. This means you’ll need to be familiar with and understand the tools needed to create this kind of project.</p>
<p>Overall, it took maybe ten minutes from the time I got the message from the client to the time I had a working React app running on my machine. A website built in ten minutes or less. This was not possible a while back, but with AI helping, you can move insanely fast.</p>
<h2 id="heading-step-4-making-the-code-actually-good">Step 4: Making the Code <em>Actually</em> Good</h2>
<p>Look, I know this is far from done. The AI gave me a great start, but it's not a finished product. I still have to plug in a CMS or a database, set up the real logic – you get the idea. This is where the <em>real</em> development starts, and AI is still my co-pilot.</p>
<h3 id="heading-what-the-ai-got-right-and-wrong">What the AI Got Right (and Wrong)</h3>
<p>The AI did a surprisingly good job on the first pass. It correctly scaffolded the Vite + React + TS project, created a <code>components</code> folder, and even used <code>shadcn/ui</code> components where I asked. This saved me at least 30-45 minutes of tedious setup.</p>
<p>But it wasn't perfect. For example, the initial data for the cars was hardcoded directly inside the component. That's a huge no-no for a real app that needs to scale or pull from a database. Also, the components weren't as reusable as I'd like.</p>
<p>This is where your job as a developer comes in – to review, refactor, and architect properly.</p>
<h3 id="heading-refactoring-in-action">Refactoring in Action</h3>
<p>I constantly go back to the AI to refine the code. I treat it like a pair programmer. Here's an example. The AI first gave me a <code>CarCard</code> component that looked something like this:</p>
<p><strong>Before Refactoring (AI's First Draft):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// components/CarCard.tsx</span>
<span class="hljs-keyword">import</span> { Button } <span class="hljs-keyword">from</span> <span class="hljs-string">"./ui/button"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> CarCard = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> carName = <span class="hljs-string">"Tesla Model S"</span>; <span class="hljs-comment">// Data is hardcoded</span>
  <span class="hljs-keyword">const</span> price = <span class="hljs-number">95</span>;

  <span class="hljs-keyword">const</span> handleRentNow = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Renting Tesla Model S"</span>);
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;h2&gt;{carName}&lt;/h2&gt;
      &lt;p&gt;${price}/day&lt;/p&gt;
      &lt;Button onClick={handleRentNow}&gt;Rent Now&lt;/Button&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<p>This is fine for a demo, but useless for a real application. So, I guided the AI to refactor it. I'd ask it something like, <em>"Refactor this</em> <code>CarCard</code> component to accept props for car data (name, price, image) and a function for the rent button click."</p>
<p><strong>After Refactoring (My Guided Version):</strong></p>
<pre><code class="lang-typescript"><span class="hljs-comment">// components/CarCard.tsx</span>
<span class="hljs-keyword">import</span> { Button } <span class="hljs-keyword">from</span> <span class="hljs-string">"./ui/button"</span>;

<span class="hljs-comment">// Define a type for the car's data</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> CarProps {
  name: <span class="hljs-built_in">string</span>;
  price: <span class="hljs-built_in">number</span>;
  imageUrl: <span class="hljs-built_in">string</span>;
}

<span class="hljs-keyword">interface</span> CarCardProps {
  car: CarProps;
  onRentNow: <span class="hljs-function">(<span class="hljs-params">carName: <span class="hljs-built_in">string</span></span>) =&gt;</span> <span class="hljs-built_in">void</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> CarCard = <span class="hljs-function">(<span class="hljs-params">{ car, onRentNow }: CarCardProps</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;img src={car.imageUrl} alt={car.name} /&gt;
      &lt;h2&gt;{car.name}&lt;/h2&gt;
      &lt;p&gt;${car.price}/day&lt;/p&gt;
      &lt;Button onClick={<span class="hljs-function">() =&gt;</span> onRentNow(car.name)}&gt;Rent Now&lt;/Button&gt;
    &lt;/div&gt;
  );
};
</code></pre>
<p>See the difference? Now it's a reusable, type-safe component that gets its data from outside. It's a back-and-forth conversation. I write some code, the AI cleans it up. The AI writes some code, I fix the logic. It's pair programming on steroids.</p>
<h2 id="heading-so-whats-the-takeaway">So, What's the Takeaway?</h2>
<p>The game has changed. AI is a tool, probably the most powerful one we've ever been given. It automates the boring stuff so we can focus on the hard problems – architecture, performance, and user experience.</p>
<p>The developers who ignore this are going to be lapped by the ones who embrace it. It’s about working smarter, not harder.</p>
<h2 id="heading-frequently-asked-questions">Frequently Asked Questions</h2>
<p>Q: What’s the best AI model to use? ChatGPT or Gemini or something else?</p>
<p>A: Honestly, they're all great at writing code, and it's all a matter of "Garbage in, Garbage out." The results you get are only as good as your prompts. But if I had to choose one right now specifically for writing and refactoring code, I'd probably pick Gemini. Your mileage may vary.</p>
<p>Q: Will I forget how to code if I rely on AI?</p>
<p>A: That's on you. If you just copy and paste without understanding what's happening, then yeah, your skills will get dull. But if you use it to learn, to see different ways of solving a problem, and to check your own work, it'll actually make you a much better developer, faster.</p>
<p>Q: Is it ethical to use AI for client work?</p>
<p>A: Of course. Your client is paying you for a working website, not for your blood, sweat, and tears typing every single bracket. Is it unethical to use a framework like React or pull in a package from npm? No. This is the same thing. It's a tool. Just make sure the final product is solid, because you're the one who is ultimately responsible for it.</p>
<p>Q: What about bugs? Does AI write perfect code?</p>
<p>A: Heck no. It will give you buggy code. It will make things up. Don't trust it blindly. My rule is to treat code from an AI like it came from a talented but very eccentric junior dev. You have to check their work. Run it, test it, and if it breaks, you can even paste the buggy code back into the AI and say, "Hey, fix this." It's surprisingly good at cleaning up its own mess.</p>
<p>If you have any questions, feel free to find me on Twitter at <a target="_blank" href="https://x.com/sprucekhalifa">@sprucekhalifa</a>, and don’t forget to follow me for more tips and updates. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Add Live Chat to Your Applications with Rocket.chat ]]>
                </title>
                <description>
                    <![CDATA[ The fastest way to gather valuable information about your site’s users is still by talking to them. And what better way to do this than by adding a chat system to your app? For my case, I just wanted to add a chat system to my portfolio website so I ]]>
                </description>
                <link>https://www.freecodecamp.org/news/add-live-chat-to-your-applications-with-rocketchat/</link>
                <guid isPermaLink="false">67f3d275332a812ead444418</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ chatbot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Mon, 07 Apr 2025 13:26:13 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1744032217209/1ad8ea61-a8bd-4bea-9bec-152e52db7377.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The fastest way to gather valuable information about your site’s users is still by talking to them. And what better way to do this than by adding a chat system to your app?</p>
<p>For my case, I just wanted to add a chat system to my portfolio website so I could get valuable info from potential employers and clients. I ended up building something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743755398731/f7bce275-ed01-4e7f-98b6-0eed955dc428.png" alt="Live chat demo screenshot" width="2742" height="1842" loading="lazy"></p>
<h3 id="heading-table-of-contents"><strong>Table of Contents</strong></h3>
<ol>
<li><p><a class="post-section-overview" href="#why-rocketchat-you-may-ask">Why</a> <a target="_blank" href="http://Rocket.Chat">Rocket.Chat</a><a class="post-section-overview" href="#why-rocketchat-you-may-ask">, you may ask?</a></p>
</li>
<li><p><a class="post-section-overview" href="#prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#getting-started">Getting Started</a></p>
<ul>
<li><p><a class="post-section-overview" href="#step-1-set-up-the-rocketchat-server">Step 1: Set Up the</a> <a target="_blank" href="http://Rocket.Chat">Rocket.Chat</a> <a class="post-section-overview" href="#step-1-set-up-the-rocketchat-server">Server</a></p>
</li>
<li><p><a class="post-section-overview" href="#step-2-configure-the-rocketchat-server">Step 2: Configure the</a> <a target="_blank" href="http://Rocket.Chat">Rocket.Chat</a> <a class="post-section-overview" href="#step-2-configure-the-rocketchat-server">Server</a></p>
</li>
<li><p><a class="post-section-overview" href="#step-3-register-the-visitor">Step 3: Register the Visitor</a></p>
<ul>
<li><p><a class="post-section-overview" href="#how-to-register-the-visitor">How to Register the Visitor</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-create-or-retrieve-the-chat-room">How to Create or Retrieve the Chat Room</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-retrieve-livechat-configuration">How to Retrieve Livechat Configuration</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#step-4-create-the-connection-to-websocket">Step 4: Create the Connection to WebSocket</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-why-rocketchat-you-may-ask">Why Rocket.Chat, you may ask?</h2>
<p>Rocket.Chat is a great option because:</p>
<ul>
<li><p><strong>Open Source:</strong> It’s free and customizable.</p>
</li>
<li><p><strong>Comprehensive APIs:</strong> Their APIs make integration simple.</p>
</li>
<li><p><strong>Flexible Hosting:</strong> Self-host your own or use their cloud version with a free trial (which we’ll use here).</p>
</li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>Before you continue, there are a few things you should know and have:</p>
<ul>
<li><p>A running Rocket.Chat server (either self-hosted or on Rocket.Chat Cloud). Here, I'll show you how to set up one with Rocket.Chat Cloud.</p>
</li>
<li><p>A working knowledge of JavaScript fundamentals.</p>
</li>
</ul>
<h2 id="heading-getting-started">Getting Started</h2>
<p>First things first, let's set up a Rocket.Chat server. Again, you can either self host your own or use their cloud version. And don't worry – you don't have to pay anything right now or for this tutorial, as they provide a 30 day free trial.</p>
<h3 id="heading-step-1-set-up-the-rocketchat-server">Step 1: Set Up the Rocket.Chat Server</h3>
<p>Head over to <a target="_blank" href="https://cloud.rocket.chat">https://cloud.rocket.chat</a> and create your free account.</p>
<p>Once you're logged in, click on the <strong>"Change to SaaS trial"</strong> button to launch a cloud-hosted server.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1743755542942/1b57e01d-2338-4af7-9a77-9140f65bb1f7.png" alt="Change to SaaS trial button" width="2742" height="1842" loading="lazy"></p>
<p>Next, create a Cloud Workspace by providing your workspace name, URL, and server region.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sdorooqpo032qjibt1vp.png" alt="Rocket.Chat Cloud Workspace screenshot" width="2742" height="1842" loading="lazy"></p>
<p>It will take a little while to set up. When it’s done, you should see something similar to this:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rcpvsdl49rw9t7bv7vfn.png" alt="Rocket.Chat dashboard screenshot" width="2742" height="1842" loading="lazy"></p>
<p>Now copy your server URL—it should look like this: <a target="_blank" href="https://example.rocket.chat"><code>https://example.rocket.chat</code></a>.</p>
<h3 id="heading-step-2-configure-the-rocketchat-server">Step 2: Configure the Rocket.Chat Server</h3>
<p>Before diving into the code, we need to configure our server so we can use the livechat API.</p>
<p>To start, open your Rocket.Chat server and click on the menu button, then click on <strong>Omnichannel</strong>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cql8hzejwep1zhxxhgg.png" alt="Rocket.Chat Omnichannel menu screenshot" width="2737" height="892" loading="lazy"></p>
<p>Click on <strong>Agents</strong> on the sidebar and add yourself as an agent.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zsnnbjsbo64h8d5zya8u.png" alt="Rocket.Chat Omnichannel Agents section screenshot" width="2742" height="1842" loading="lazy"></p>
<p>Next, click on <strong>Departments</strong> and create a Department. I'll call mine <strong>Chats</strong>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ej4n16odg3iy578ltna0.png" alt="Rocket.Chat Omnichannel Departments section screenshot" width="2742" height="1842" loading="lazy"></p>
<p>Now you need to configure a few things about the Livechat widget:</p>
<ul>
<li><p>Make sure you turn on the offline form and set the Email Address to Send Offline Messages.</p>
</li>
<li><p>Also, configure your business hours to the times you'll be available.</p>
</li>
</ul>
<h3 id="heading-step-3-register-the-visitor">Step 3: Register the Visitor</h3>
<p>Next, we need to register the visitor and create a room for them. To do this, you need to collect the visitor's name and email and generate a random unique ID.</p>
<h4 id="heading-how-to-register-the-visitor">How to Register the Visitor</h4>
<p>First, we need to register the visitor in the server. We need their name, email, and token. You send those to this endpoint: <code>/api/v1/livechat/visitor</code>. Here's an example code that you might send from your backend:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> body = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Visitor Name"</span>,          <span class="hljs-comment">// Replace with the visitor's name</span>
  <span class="hljs-attr">email</span>: <span class="hljs-string">"visitor@example.com"</span>,  <span class="hljs-comment">// Replace with the visitor's email</span>
  <span class="hljs-attr">token</span>: <span class="hljs-string">"unique-visitor-token"</span>  <span class="hljs-comment">// Replace with a generated unique token</span>
};

fetch(<span class="hljs-string">`<span class="hljs-subst">${process.env.ROCKETCHAT_URL}</span>/api/v1/livechat/visitor`</span>, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
  <span class="hljs-attr">headers</span>: {
    <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,
    <span class="hljs-string">'Cache-Control'</span>: <span class="hljs-string">'no-cache'</span>
  },
  <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(body)
})
  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (data.success) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Visitor registered:"</span>, data);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Visitor registration failed:"</span>, data);
    }
  })
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error in visitor registration:"</span>, error));
</code></pre>
<h4 id="heading-how-to-create-or-retrieve-the-chat-room">How to Create or Retrieve the Chat Room</h4>
<p>After you've registered the visitor, you need to create a room for them so they can send you messages and you can respond.</p>
<p>Call this endpoint <code>/api/v1/livechat/room</code> with the visitor token as a query parameter. If the visitor already has a room, it’ll be returned. If not, a new one will be created. This is how you can make that request from your backend:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> token = <span class="hljs-string">"unique-visitor-token"</span>; <span class="hljs-comment">// Replace with the actual visitor token</span>

fetch(<span class="hljs-string">`<span class="hljs-subst">${process.env.ROCKETCHAT_URL}</span>/api/v1/livechat/room?token=<span class="hljs-subst">${token}</span>`</span>, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span>,
  <span class="hljs-attr">headers</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
})
  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (data.success) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Room retrieved:"</span>, data);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Failed to retrieve room:"</span>, data);
    }
  })
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error in retrieving room:"</span>, error));
</code></pre>
<h4 id="heading-how-to-retrieve-livechat-configuration">How to Retrieve Livechat Configuration</h4>
<p>Lastly, we need to get the info about the visitor and the agent we registered. Use this API endpoint to get the visitor token, room ID, and agent info. You can use it to check if the agent is online before trying to connect to the WebSocket.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> token = <span class="hljs-string">"unique-visitor-token"</span>; <span class="hljs-comment">// Replace with the actual visitor token</span>
<span class="hljs-keyword">const</span> url = <span class="hljs-string">`<span class="hljs-subst">${process.env.ROCKETCHAT_URL}</span>/api/v1/livechat/config?token=<span class="hljs-subst">${token}</span>`</span>;

fetch(url, {
  <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span>,
  <span class="hljs-attr">headers</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
})
  .then(<span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> response.json())
  .then(<span class="hljs-function"><span class="hljs-params">data</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (data.success) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Livechat config:"</span>, data);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Failed to get livechat config:"</span>, data);
    }
  })
  .catch(<span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error fetching livechat config:"</span>, error));
</code></pre>
<h3 id="heading-step-4-create-the-connection-to-websocket">Step 4: Create the Connection to WebSocket</h3>
<p>To establish the live chat experience, we need to open a WebSocket connection to Rocket.Chat and handle messaging.</p>
<h4 id="heading-websocket-connection-example">WebSocket Connection Example</h4>
<p>First, open the WebSocket like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> rocketChatSocket = <span class="hljs-keyword">new</span> WebSocket(<span class="hljs-string">"ws://example.rocket.chat/websocket"</span>);
</code></pre>
<p>Then connect:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> connectRequest = {
  <span class="hljs-attr">msg</span>: <span class="hljs-string">"connect"</span>,
  <span class="hljs-attr">version</span>: <span class="hljs-string">"1"</span>,
  <span class="hljs-attr">support</span>: [<span class="hljs-string">"1"</span>, <span class="hljs-string">"pre2"</span>, <span class="hljs-string">"pre1"</span>]
};
rocketChatSocket.send(<span class="hljs-built_in">JSON</span>.stringify(connectRequest));
</code></pre>
<p>You can keep the connection alive by responding to the server's <code>"ping"</code> messages with a <code>"pong"</code>.</p>
<pre><code class="lang-js">rocketChatSocket.onmessage = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> data = <span class="hljs-built_in">JSON</span>.parse(event.data);
    <span class="hljs-keyword">if</span> (data.msg === <span class="hljs-string">"ping"</span>) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Received ping from server, sending pong"</span>);
      rocketChatSocket.send(<span class="hljs-built_in">JSON</span>.stringify({ <span class="hljs-attr">msg</span>: <span class="hljs-string">"pong"</span> }));
    }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error parsing WebSocket message:"</span>, error);
  }
};
</code></pre>
<p>You can subscribe to the room created for the visitor. Just use the visitor’s token and room ID from the previous sections.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> subscribeRequest = {
  <span class="hljs-attr">msg</span>: <span class="hljs-string">"sub"</span>,
  <span class="hljs-attr">id</span>: <span class="hljs-string">"unique-subscription-id"</span>, <span class="hljs-comment">// Replace with your unique ID</span>
  <span class="hljs-attr">name</span>: <span class="hljs-string">"stream-room-messages"</span>,
  <span class="hljs-attr">params</span>: [
    <span class="hljs-string">"fetched-room-id"</span>, <span class="hljs-comment">// Replace with the room ID variable</span>
    {
      <span class="hljs-attr">useCollection</span>: <span class="hljs-literal">false</span>,
      <span class="hljs-attr">args</span>: [
        { <span class="hljs-attr">visitorToken</span>: <span class="hljs-string">"visitor-token"</span> } <span class="hljs-comment">// Replace with your visitor token variable</span>
      ],
    },
  ],
};
rocketChatSocket.send(<span class="hljs-built_in">JSON</span>.stringify(subscribeRequest));
</code></pre>
<p>You can also listen for incoming messages. Here’s how you can process new messages as they arrive:</p>
<pre><code class="lang-js">rocketChatSocket.onmessage = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> data = <span class="hljs-built_in">JSON</span>.parse(event.data);
    <span class="hljs-keyword">if</span> (
      data.msg === <span class="hljs-string">"changed"</span> &amp;&amp;
      data.collection === <span class="hljs-string">"stream-room-messages"</span>
    ) {
      <span class="hljs-comment">// Handle new messages</span>
      <span class="hljs-keyword">if</span> (data.fields &amp;&amp; data.fields.args &amp;&amp; data.fields.args.length &gt; <span class="hljs-number">0</span>) {
        <span class="hljs-keyword">const</span> newMessage = data.fields.args[<span class="hljs-number">0</span>];
        <span class="hljs-comment">// Assume isValidChatMessage is defined to validate the message format</span>
        <span class="hljs-keyword">if</span> (isValidChatMessage(newMessage)) {
          <span class="hljs-comment">// Update your messages list here</span>
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"New message received:"</span>, newMessage);
        }
      }
    }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error parsing WebSocket message:"</span>, error);
  }
};
</code></pre>
<p>What if you want to send livechat messages? Just use this code to do so:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> sendMessageRequest = {
  <span class="hljs-attr">msg</span>: <span class="hljs-string">"method"</span>,
  <span class="hljs-attr">method</span>: <span class="hljs-string">"sendMessageLivechat"</span>,
  <span class="hljs-attr">params</span>: [
    {
      <span class="hljs-attr">_id</span>: <span class="hljs-string">"unique-message-id"</span>,  <span class="hljs-comment">// Replace with a generated unique ID for the message</span>
      <span class="hljs-attr">rid</span>: <span class="hljs-string">"room-id"</span>,            <span class="hljs-comment">// Replace with the actual room ID</span>
      <span class="hljs-attr">msg</span>: <span class="hljs-string">"Your message here"</span>,  <span class="hljs-comment">// Replace with the message text you want to send</span>
      <span class="hljs-attr">token</span>: <span class="hljs-string">"visitor-token"</span>     <span class="hljs-comment">// Replace with the actual visitor token</span>
    }
  ],
  <span class="hljs-attr">id</span>: <span class="hljs-string">"unique-request-id"</span>        <span class="hljs-comment">// Replace with a unique request ID</span>
};

rocketChatSocket.send(<span class="hljs-built_in">JSON</span>.stringify(sendMessageRequest));
</code></pre>
<p>In your actual implementation, you can integrate these examples into your backend or client-side logic as needed.</p>
<p>You can take a look at the <a target="_blank" href="https://github.com/iamspruce/resume">source code</a> for how I implemented mine with Next.js or you can look at the live <a target="_blank" href="https://resume-alpha-jet-70.vercel.app">demo</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Adding a Livechat feature to your web apps shouldn't be hard. With Rocket.Chat's livechat API, you can quickly integrate chat functionality and gain valuable insights from your users. I even built an <a target="_blank" href="https://www.npmjs.com/package/rocketchat-livechat-sdk">SDK wrapper</a> to make it easier to use.</p>
<p>Now it’s your turn! Try out Rocket.Chat’s API and build your own live chat system. You can explore more in the Rocket.Chat <a target="_blank" href="https://docs.rocket.chat">documentation</a>.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Reusable useSearch Hook in React ]]>
                </title>
                <description>
                    <![CDATA[ Recently, I needed to add a search feature to a React app. Naturally, I did what many developers would do—I turned to Google for help. The first article I found was about building a search and filter component in React. As I read through it, I couldn... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-reusable-usesearch-hook-in-react/</link>
                <guid isPermaLink="false">67be32ff803613c5edf10387</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ReactHooks ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Tue, 25 Feb 2025 21:15:43 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1740494925672/3a87e5a2-5233-4fae-a652-4fbf5b325ded.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Recently, I needed to add a search feature to a React app. Naturally, I did what many developers would do—I turned to Google for help.</p>
<p>The first article I found was about building a search and filter component in React. As I read through it, I couldn't help but think, <em>This is okay, but it misses so many important cases.</em> Then it hit me—I was the one who wrote that article a few years ago.</p>
<p>Turns out, my past self had some learning to do.</p>
<p>Since then, I've tackled more complex projects and realized that search in React can be so much more powerful, flexible, and efficient. That's why I've developed a reusable useSearch hook that handles everything from large datasets to typo-tolerant searches—and I'm excited to share it with you.</p>
<p>In this article, I'll walk you through building it step by step. By the end, you'll have a high-performance search system that you can drop into any React project, no matter how complex your data gets.</p>
<h2 id="heading-outline">Outline</h2>
<ul>
<li><p><a class="post-section-overview" href="#introduction">Introduction</a></p>
</li>
<li><p><a class="post-section-overview" href="#the-problem-with-simple-search-implementations">The Problem With Simple Search Implementations</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-build-a-reusable-usesearch-hook">How to Build a Reusable useSearch Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-create-the-filters">How to Create the Filters</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-handle-typos-in-search">How to Handle Typos in Search</a></p>
</li>
<li><p><a class="post-section-overview" href="#how-to-use-the-ready-made-usesearch-hook">How to Use the Ready-Made useSearch Hook</a></p>
</li>
<li><p><a class="post-section-overview" href="#conclusion">Conclusion</a></p>
</li>
</ul>
<h3 id="heading-who-should-read-this">Who Should Read This?</h3>
<p>If you’re a React developer, whether you're just getting started or have plenty of experience, you’ve probably run into the limits of basic search features. Maybe your search is sluggish with large datasets, struggles with typos, or isn’t flexible enough to handle different data structures. If that sounds familiar, this guide is for you. We’ll build a high-performance, reusable search system that actually works in real-world apps.</p>
<h3 id="heading-what-youll-learn">What You’ll Learn</h3>
<p>By the end of this guide, you’ll know how to:</p>
<ul>
<li><p>Spot the common pitfalls of simple search implementations.</p>
</li>
<li><p>Build a powerful <code>useSearch</code> hook that works with different data types and nested objects.</p>
</li>
<li><p>Optimize performance with techniques like debouncing and memoization.</p>
</li>
<li><p>Improve the user experience with fuzzy search that handles typos.</p>
</li>
<li><p>Implement pagination to efficiently manage large result sets.</p>
</li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>Before diving in, you should be comfortable with:</p>
<ul>
<li><p>React and JavaScript fundamentals.</p>
</li>
<li><p>Basic React hooks such as <code>useState</code> and <code>useEffect</code>.</p>
</li>
<li><p>Working with arrays and objects in JavaScript.</p>
</li>
</ul>
<h2 id="heading-the-problem-with-simple-search-implementations">The Problem With Simple Search Implementations</h2>
<p>Let’s start with a basic search component:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SimpleSearch</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> data = [
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"JavaScript"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Python"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Java"</span> }
    ];

    <span class="hljs-keyword">const</span> [query, setQuery] = useState(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">const</span> results = data.filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> item.name.includes(query));

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{query}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setQuery(e.target.value)}
                placeholder="Search..."
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
                {results.map((item, index) =&gt; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>{item.name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                ))}
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/NPKJyyR" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>At first glance, this works fine: you type a query and get matching results. But in real-world applications, search needs to handle much more than just simple string comparisons. Here are some major limitations:</p>
<ul>
<li><p><strong>Limited data support:</strong> This approach only works with plain strings, making it impractical for complex data structures.</p>
</li>
<li><p><strong>No support for nested objects:</strong> If your data has deeper structures (for example, <code>{ user: { name: "JavaScript" } }</code>), this won’t work.</p>
</li>
<li><p><strong>No typo tolerance:</strong> A slight misspelling like <code>"javascrpt"</code> won’t match <code>"JavaScript"</code>, which can frustrate users.</p>
</li>
<li><p><strong>Performance bottlenecks:</strong> Every keystroke triggers a full re-render, which can cause lag, especially with large datasets.</p>
</li>
</ul>
<p>Clearly, we need something more powerful. Let’s build a better search system that’s flexible, optimized, and user-friendly.</p>
<h2 id="heading-how-to-build-a-reusable-usesearch-hook">How to Build a Reusable <code>useSearch</code> Hook</h2>
<p>To overcome these issues, we’ll build a reusable <code>useSearch</code> hook that:</p>
<ul>
<li><p>Supports multiple data types (strings, numbers, dates, nested objects).</p>
</li>
<li><p>Improves performance using debouncing and memoization.</p>
</li>
<li><p>Handles typos with fuzzy search.</p>
</li>
</ul>
<h3 id="heading-how-to-create-the-hook">How to Create the Hook</h3>
<p>Let’s start by creating the hook. It takes in data, the search query, and a list of filter functions to apply:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// hooks/useSearch.js</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useSearch</span>(<span class="hljs-params">data, query, ...filters</span>) </span>{
    <span class="hljs-keyword">const</span> debouncedQuery = useDebounce(query, <span class="hljs-number">300</span>);

    <span class="hljs-keyword">return</span> React.useMemo(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> dataArray = <span class="hljs-built_in">Array</span>.isArray(data) ? data : [data];

        <span class="hljs-keyword">try</span> {
            <span class="hljs-comment">// Apply each filter function in sequence</span>
            <span class="hljs-keyword">return</span> filters.reduce(
                <span class="hljs-function">(<span class="hljs-params">acc, feature</span>) =&gt;</span> feature(acc, debouncedQuery),
                dataArray
            );
        } <span class="hljs-keyword">catch</span> (error) {
            <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error applying search features:"</span>, error);
            <span class="hljs-keyword">return</span> dataArray;
        }
    }, [data, debouncedQuery, filters]);
}
</code></pre>
<h3 id="heading-how-to-handle-the-query-with-usedebounce">How to Handle the Query with <code>useDebounce</code></h3>
<p>Without debouncing, every single keystroke triggers a new search. Imagine typing <code>"apple"</code>—each letter (<code>a</code>, <code>p</code>, <code>p</code>, <code>l</code>, <code>e</code>) fires a search request, causing multiple re-renders and potential performance issues.</p>
<p>To fix this, we used a debounce mechanism in the <code>useSearch</code> hook that waits until the user stops typing before running the search. Here’s what the <code>useDebounce</code> hook looks like:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">useDebounce</span>(<span class="hljs-params">value, delay</span>) </span>{
    <span class="hljs-keyword">const</span> [debouncedValue, setDebouncedValue] = React.useState(value);

    React.useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> timeoutId = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
            setDebouncedValue(value);
        }, delay);

        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearTimeout</span>(timeoutId);
    }, [value, delay]);

    <span class="hljs-keyword">return</span> debouncedValue;
}
</code></pre>
<p>This hook ensures that the search only triggers after 300ms of inactivity, preventing unnecessary re-renders and improving responsiveness.</p>
<p>Want to see the difference in action? Compare a debounced search to one that updates on every keystroke in the demo below:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/pvzYaXp" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h3 id="heading-how-to-optimize-performance-with-reactusememo">How to Optimize Performance with <code>React.useMemo</code></h3>
<p>Filtering large datasets can be expensive, and if our search logic runs every time a component re-renders—even when the search query hasn’t changed—it can slow things down. That’s where <code>React.useMemo()</code> comes in.</p>
<p>By wrapping our search logic in <code>useMemo</code>, we ensure it only recalculates when the search query, filters, or data actually change:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">return</span> React.useMemo(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Filtering logic</span>
}, [data, debouncedQuery, filters]);
</code></pre>
<p>But how much of a difference does this make? Imagine a parent component with an unrelated state (like a counter). Every time the parent re-renders, a non-memoized search would still run, even if the query remains the same.</p>
<p>The live demo below compares two search implementations, one without <code>useMemo</code> and one with it. Try changing an unrelated state in the parent and see how many times each search runs:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/EaYMEar" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>With <code>useMemo</code>, the search logic only runs when the query, filters, or data change, keeping performance smooth and avoiding unnecessary computations.</p>
<h3 id="heading-how-to-chain-filters-with-reduce">How to Chain Filters with <code>.reduce()</code></h3>
<p>The hook uses <code>.reduce()</code> to sequentially apply each filter function to the data, keeping the logic clean and modular:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">return</span> filters.reduce(
    <span class="hljs-function">(<span class="hljs-params">acc, feature</span>) =&gt;</span> feature(acc, debouncedQuery),
    dataArray
);
</code></pre>
<p>This approach makes it easy to add or remove filters as needed.</p>
<h2 id="heading-how-to-create-the-filters">How to Create the Filters</h2>
<p>Filters add the magic to our search hook by processing the data based on the search query. For this project, I created two filters: one for searching and one for pagination.</p>
<h3 id="heading-1-the-search-filter">1. The Search Filter</h3>
<p>The search filter checks specified fields in an object for matches with the query. It supports several matching strategies (exact, startsWith, endsWith, contains):</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// utils/search.js</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params">options</span>) </span>{
    <span class="hljs-keyword">const</span> { fields, matchType } = options;

    <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">data, query</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> trimmedQuery = <span class="hljs-built_in">String</span>(query).trim().toLowerCase();

        <span class="hljs-keyword">if</span> (!trimmedQuery) <span class="hljs-keyword">return</span> data;

        <span class="hljs-keyword">return</span> data.filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> fieldsArray = fields
                ? <span class="hljs-built_in">Array</span>.isArray(fields)
                    ? fields
                    : [fields]
                : getAllKeys(item);

            <span class="hljs-keyword">return</span> fieldsArray.some(<span class="hljs-function">(<span class="hljs-params">field</span>) =&gt;</span> {
                <span class="hljs-keyword">const</span> fieldValue = getFieldValue(item, field);
                <span class="hljs-keyword">if</span> (fieldValue == <span class="hljs-literal">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;

                <span class="hljs-keyword">const</span> stringValue = convertToString(fieldValue).toLowerCase();

                <span class="hljs-keyword">switch</span> (matchType) {
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"exact"</span>:
                        <span class="hljs-keyword">return</span> stringValue === trimmedQuery;
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"startsWith"</span>:
                        <span class="hljs-keyword">return</span> stringValue.startsWith(trimmedQuery);
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"endsWith"</span>:
                        <span class="hljs-keyword">return</span> stringValue.endsWith(trimmedQuery);
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"contains"</span>:
                        <span class="hljs-keyword">return</span> stringValue.includes(trimmedQuery);
                    <span class="hljs-keyword">default</span>:
                        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Unsupported match type: <span class="hljs-subst">${matchType}</span>`</span>);
                }
            });
        });
    };
}
</code></pre>
<p>Let’s go through it to see how it works:</p>
<ol>
<li><p>Cleaning up the query:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> trimmedQuery = <span class="hljs-built_in">String</span>(query).trim().toLowerCase();

 <span class="hljs-keyword">if</span> (!trimmedQuery) {
     <span class="hljs-keyword">return</span> data;
 }
</code></pre>
<p> This makes the search case-insensitive and removes extra spaces.</p>
</li>
<li><p>Determining fields to search:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> fieldsArray = fields
     ? <span class="hljs-built_in">Array</span>.isArray(fields)
         ? fields
         : [fields]
     : getAllKeys(item);
</code></pre>
<p> If specific fields aren’t provided, it extracts all keys, including nested ones.</p>
</li>
<li><p>Filtering the data:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">return</span> fieldsArray.some(<span class="hljs-function">(<span class="hljs-params">field</span>) =&gt;</span> {
     <span class="hljs-keyword">const</span> fieldValue = getFieldValue(item, field);

     <span class="hljs-keyword">if</span> (fieldValue == <span class="hljs-literal">null</span>) {
         <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
     }

     <span class="hljs-keyword">const</span> stringValue = convertToString(fieldValue).toLowerCase();

     <span class="hljs-comment">// Matching logic based on matchType follows...</span>
 });
</code></pre>
</li>
</ol>
<h3 id="heading-2-the-helper-functions">2. The Helper Functions</h3>
<p>To keep our filtering logic clean and focused, we use a few helper functions. These functions handle common tasks like retrieving keys from an object, getting nested field values, and converting values to strings. This way, our search filter can work with a variety of data structures and types without cluttering the main logic.</p>
<ul>
<li><p>Extracting all keys with <code>getAllKeys</code>:</p>
<p>  The <code>getAllKeys</code> function scans an object to gather all its keys—even those nested within arrays or sub-objects. If you don't provide specific fields for searching, this function ensures that every potential field is considered.</p>
<pre><code class="lang-javascript">  <span class="hljs-comment">// utils/getAllKeys.js</span>

  <span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getAllKeys</span>(<span class="hljs-params">item, prefix = <span class="hljs-string">""</span></span>) </span>{
      <span class="hljs-keyword">if</span> (!item || <span class="hljs-keyword">typeof</span> item !== <span class="hljs-string">"object"</span>) {
          <span class="hljs-keyword">return</span> [];
      }

      <span class="hljs-keyword">const</span> fields = [];

      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">of</span> <span class="hljs-built_in">Object</span>.keys(item)) {
          <span class="hljs-keyword">const</span> value = item[key];
          <span class="hljs-keyword">const</span> fieldPath = prefix ? <span class="hljs-string">`<span class="hljs-subst">${prefix}</span>.<span class="hljs-subst">${key}</span>`</span> : key;

          <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(value)) {
              value.forEach(<span class="hljs-function">(<span class="hljs-params">arrayItem, index</span>) =&gt;</span> {
                  <span class="hljs-keyword">if</span> (
                      arrayItem &amp;&amp;
                      <span class="hljs-keyword">typeof</span> arrayItem === <span class="hljs-string">"object"</span> &amp;&amp;
                      !(arrayItem <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Date</span>)
                  ) {
                      fields.push(...getAllKeys(arrayItem, <span class="hljs-string">`<span class="hljs-subst">${fieldPath}</span>[<span class="hljs-subst">${index}</span>]`</span>));
                  } <span class="hljs-keyword">else</span> {
                      fields.push(<span class="hljs-string">`<span class="hljs-subst">${fieldPath}</span>[<span class="hljs-subst">${index}</span>]`</span>);
                  }
              });
          } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Date</span>) {
              fields.push(fieldPath);
          } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value &amp;&amp; <span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"object"</span>) {
              fields.push(...getAllKeys(value, fieldPath));
          } <span class="hljs-keyword">else</span> {
              fields.push(fieldPath);
          }
      }

      <span class="hljs-keyword">return</span> fields;
  }
</code></pre>
</li>
<li><p>Retrieving field values with <code>getFieldValue</code>:</p>
<p>  The <code>getFieldValue</code> function extracts the value of a given field from an object using a path string (like <code>"</code><a target="_blank" href="http://user.name"><code>user.name</code></a><code>"</code> or <code>"items[0].title"</code>). It splits the path into individual keys and then traverses the object step by step to find the correct value.</p>
<pre><code class="lang-javascript">  <span class="hljs-comment">// utils/getFieldValue.js</span>

  <span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getFieldValue</span>(<span class="hljs-params">item, field</span>) </span>{
      <span class="hljs-keyword">const</span> keys = field.split(<span class="hljs-regexp">/[\.\[\]]/</span>).filter(<span class="hljs-built_in">Boolean</span>);
      <span class="hljs-keyword">let</span> value = item;

      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">of</span> keys) {
          <span class="hljs-keyword">if</span> (value == <span class="hljs-literal">null</span>) {
              <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
          }
          value = value[key];
      }

      <span class="hljs-keyword">return</span> value;
  }
</code></pre>
</li>
<li><p>Converting values to strings with <code>convertToString</code>:</p>
<p>  For our search comparisons, we need to ensure all data is in string format. The <code>convertToString</code> function handles this conversion. It turns dates into ISO strings and booleans into <code>"true"</code> or <code>"false"</code>, ensuring a uniform format for our search filter.</p>
<pre><code class="lang-javascript">  <span class="hljs-comment">// utils/convertToString.js</span>

  <span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">convertToString</span>(<span class="hljs-params">value</span>) </span>{
      <span class="hljs-keyword">if</span> (value <span class="hljs-keyword">instanceof</span> <span class="hljs-built_in">Date</span>) {
          <span class="hljs-keyword">return</span> value.toISOString();
      }

      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> value === <span class="hljs-string">"boolean"</span>) {
          <span class="hljs-keyword">return</span> value ? <span class="hljs-string">"true"</span> : <span class="hljs-string">"false"</span>;
      }

      <span class="hljs-keyword">return</span> <span class="hljs-built_in">String</span>(value);
  }
</code></pre>
</li>
</ul>
<h3 id="heading-3-the-pagination-filter">3. The Pagination Filter</h3>
<p>For large datasets, displaying all results at once isn't practical. The pagination filter helps by returning only a subset of the data based on the current page and the number of items per page. This not only improves performance but also makes the data more manageable for users.</p>
<p>In this function, we calculate the starting index by using the current page number and page size. Then, we use the JavaScript <code>slice</code> method to pick out only the items that belong to that specific page. Although the query parameter is present, it isn’t used here—it’s just for keeping the hook's interface consistent.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// utils/paginate.js</span>

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">paginate</span>(<span class="hljs-params">options</span>) </span>{
    <span class="hljs-keyword">const</span> { page = <span class="hljs-number">1</span>, pageSize = <span class="hljs-number">10</span> } = options;

    <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">data, query</span>) =&gt;</span> {
        <span class="hljs-comment">// Query is not used here; it’s only for compatibility with our hook.</span>
        <span class="hljs-keyword">const</span> startIndex = (page - <span class="hljs-number">1</span>) * pageSize;

        <span class="hljs-keyword">return</span> data.slice(startIndex, startIndex + pageSize);
    };
}
</code></pre>
<p>In this code, the pagination filter efficiently slices the data array, so you only get the subset of results that you want to display on the current page.</p>
<h2 id="heading-how-to-use-the-hook-with-search-and-pagination-filters">How to Use the Hook with Search and Pagination Filters</h2>
<p>Now that we have both the search and pagination filters set up, let’s see how to use them in a React component.</p>
<p>First, import the custom <code>useSearch</code> hook and the filter functions:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> useSearch <span class="hljs-keyword">from</span> <span class="hljs-string">"./hooks/useSearch.js"</span>;
<span class="hljs-keyword">import</span> search <span class="hljs-keyword">from</span> <span class="hljs-string">"./utils/search.js"</span>;
<span class="hljs-keyword">import</span> paginate <span class="hljs-keyword">from</span> <span class="hljs-string">"./utils/paginate.js"</span>;
</code></pre>
<p>Next, create a component that uses these filters. In this example, we have an array of items, and we want to search by name and display a fixed number of results per page. We also reset to the first page whenever a new search query is entered.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SearchComponent</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Example data array</span>
    <span class="hljs-keyword">const</span> data = [
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"JavaScript"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Python"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Java"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Ruby"</span> },
        <span class="hljs-comment">// Imagine more data here</span>
    ];

    <span class="hljs-keyword">const</span> [query, setQuery] = React.useState(<span class="hljs-string">""</span>);
    <span class="hljs-keyword">const</span> [page, setPage] = React.useState(<span class="hljs-number">1</span>);
    <span class="hljs-keyword">const</span> pageSize = <span class="hljs-number">3</span>; <span class="hljs-comment">// Items per page</span>

    <span class="hljs-comment">// Apply both search and pagination filters with our custom hook.</span>
    <span class="hljs-keyword">const</span> results = useSearch(
        data,
        query,
        search({
            <span class="hljs-attr">fields</span>: [<span class="hljs-string">"name"</span>],
            <span class="hljs-attr">matchType</span>: <span class="hljs-string">"contains"</span>, <span class="hljs-comment">// Options: "exact", "startsWith", etc.</span>
        }),
        paginate({ page, pageSize })
    );

    <span class="hljs-comment">// Compute total pages based on filtered results (without pagination)</span>
    <span class="hljs-keyword">const</span> filteredData = search({ <span class="hljs-attr">fields</span>: [<span class="hljs-string">"name"</span>], <span class="hljs-attr">matchType</span>: <span class="hljs-string">"contains"</span> })(
        data,
        query
    );

    <span class="hljs-keyword">const</span> totalPages = <span class="hljs-built_in">Math</span>.ceil(filteredData.length / pageSize);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">padding:</span> "<span class="hljs-attr">20px</span>", <span class="hljs-attr">fontFamily:</span> "<span class="hljs-attr">Arial</span>, <span class="hljs-attr">sans-serif</span>" }}&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Search and Pagination<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{query}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> {
                    setQuery(e.target.value);
                    setPage(1); // Reset to first page on new search
                }}
                placeholder="Search by name..."
                style={{ padding: "8px", width: "300px", marginBottom: "10px" }}
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
                {results.map((item, index) =&gt; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>{item.name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                ))}
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">marginTop:</span> "<span class="hljs-attr">10px</span>" }}&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setPage((prev) =&gt; Math.max(prev - 1, 1))}
                    disabled={page === 1}
                    style={{ padding: "6px 12px", marginRight: "10px" }}
                &gt;
                    Previous
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>Page {page} of {totalPages}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setPage((prev) =&gt; Math.min(prev + 1, totalPages))}
                    disabled={page &gt;= totalPages}
                    style={{ padding: "6px 12px", marginLeft: "10px" }}
                &gt;
                    Next
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<p>To see this in action and try it for yourself, check out the live demo below:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/xbKerxQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-how-to-handle-typos-in-search">How to Handle Typos in Search</h2>
<p>Search is one of the oldest features on the web, but that doesn’t mean users always get it right. In fact, typos are incredibly common. Imagine a user searching for "PlayStation," but they accidentally type "PlauStation" instead. They still expect to see relevant results, and our search system should be forgiving enough to handle these small mistakes.</p>
<p>To achieve this, we are going to use a fuzzy search technique that matches similar words even if they’re not spelled exactly the same. We’ll implement this using an <strong>n-gram similarity algorithm</strong>, which breaks words into smaller segments (n-grams) and compares them to find matches.</p>
<h3 id="heading-step-1-building-the-n-gram-similarity-algorithm">Step 1: Building the n-gram Similarity Algorithm</h3>
<p>The n-gram similarity algorithm works by splitting both the search query and dataset values into small overlapping character sequences (n-grams) and comparing them:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// utils/nGramFuzzySearch.js</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> nGramFuzzySearch = <span class="hljs-function">(<span class="hljs-params">value, query</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> n = <span class="hljs-number">2</span>; <span class="hljs-comment">// Default to bigrams (two-character sequences)</span>

    <span class="hljs-keyword">const</span> valueGrams = generateNGrams(value.toLowerCase(), n);
    <span class="hljs-keyword">const</span> queryGrams = generateNGrams(query.toLowerCase(), n);

    <span class="hljs-keyword">const</span> intersection = valueGrams.filter(<span class="hljs-function">(<span class="hljs-params">gram</span>) =&gt;</span> queryGrams.includes(gram));

    <span class="hljs-keyword">return</span> intersection.length / <span class="hljs-built_in">Math</span>.max(valueGrams.length, queryGrams.length);
};

<span class="hljs-keyword">const</span> generateNGrams = <span class="hljs-function">(<span class="hljs-params">str, n</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> grams = [];

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt;= str.length - n; i++) {
        grams.push(str.slice(i, i + n));
    }

    <span class="hljs-keyword">return</span> grams;
};
</code></pre>
<p>Here is how this will work if you try searching for query PlauStation and the product name is PlayStation:</p>
<p>First, the algorithm will generate bigrams (two-letter sequences) for both words:</p>
<p><code>PlayStation</code> → <code>["pl", "la", "ay", "ys", "st", "ta", "at", "ti", "io", "on"]</code><br><code>PlauStation</code> → <code>["pl", "la", "au", "us", "st", "ta", "at", "ti", "io", "on"]</code></p>
<p>Then, it calculates the similarity based on the number of overlapping bigrams. The higher the overlap, the closer the match. Since most bigrams match, the algorithm calculates a high similarity score, allowing it to recognize "PlauStation" as a likely match for "PlayStation", even with minor typos.</p>
<h3 id="heading-step-2-adding-fuzzy-search-into-the-search-filter">Step 2: Adding Fuzzy Search into the Search Filter</h3>
<p>Now, update your search filter to support a new <code>matchType</code> for fuzzy search:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Update in utils/search.js</span>

<span class="hljs-keyword">import</span> { nGramFuzzySearch } <span class="hljs-keyword">from</span> <span class="hljs-string">"./nGramFuzzySearch"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span>(<span class="hljs-params">options</span>) </span>{
    <span class="hljs-keyword">const</span> { fields, matchType } = options;

    <span class="hljs-keyword">return</span> <span class="hljs-function">(<span class="hljs-params">data, query</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> trimmedQuery = <span class="hljs-built_in">String</span>(query).trim().toLowerCase();

        <span class="hljs-keyword">if</span> (trimmedQuery === <span class="hljs-string">""</span>) {
            <span class="hljs-keyword">return</span> data;
        }

        <span class="hljs-keyword">return</span> data.filter(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> {
            <span class="hljs-keyword">const</span> fieldsArray = fields
                ? <span class="hljs-built_in">Array</span>.isArray(fields)
                    ? fields
                    : [fields]
                : getAllKeys(item);

            <span class="hljs-keyword">return</span> fieldsArray.some(<span class="hljs-function">(<span class="hljs-params">field</span>) =&gt;</span> {
                <span class="hljs-keyword">const</span> fieldValue = getFieldValue(item, field);
                <span class="hljs-keyword">if</span> (fieldValue == <span class="hljs-literal">null</span>) {
                    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
                }

                <span class="hljs-keyword">const</span> stringValue = convertToString(fieldValue).toLowerCase();

                <span class="hljs-keyword">switch</span> (matchType) {
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"exact"</span>:
                        <span class="hljs-keyword">return</span> stringValue === trimmedQuery;
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"startsWith"</span>:
                        <span class="hljs-keyword">return</span> stringValue.startsWith(trimmedQuery);
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"endsWith"</span>:
                        <span class="hljs-keyword">return</span> stringValue.endsWith(trimmedQuery);
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"contains"</span>:
                        <span class="hljs-keyword">return</span> stringValue.includes(trimmedQuery);
                    <span class="hljs-keyword">case</span> <span class="hljs-string">"fuzzySearch"</span>: {
                        <span class="hljs-keyword">const</span> threshold = <span class="hljs-number">0.5</span>; <span class="hljs-comment">// Minimum similarity score required</span>
                        <span class="hljs-keyword">const</span> score = nGramFuzzySearch(stringValue, trimmedQuery);
                        <span class="hljs-keyword">return</span> score &gt;= threshold;
                    }
                    <span class="hljs-attr">default</span>:
                        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">`Unsupported match type: <span class="hljs-subst">${matchType}</span>`</span>);
                }
            });
        });
    };
}
</code></pre>
<h3 id="heading-step-3-using-fuzzy-search-in-the-usesearch-hook">Step 3: Using Fuzzy Search in the <code>useSearch</code> Hook</h3>
<p>Now you can enable fuzzy search simply by passing <code>fuzzySearch</code> as the <code>matchType</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> results = useSearch(
    data,
    query,
    search({
        <span class="hljs-attr">fields</span>: [<span class="hljs-string">"name"</span>],
        <span class="hljs-attr">matchType</span>: <span class="hljs-string">"fuzzySearch"</span>,
    })
);
</code></pre>
<p>Try it out on this <a target="_blank" href="https://codepen.io/Spruce_khalifa/pen/bNbZQNW?editors=0011">Live Demo</a> to see how even with a typo like <code>"PlauStation"</code>, your app still finds <code>"PlayStation"</code>.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/bNbZQNW" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-how-to-use-the-ready-made-usesearch-hook">How to Use the Ready-Made <code>useSearch</code> Hook</h2>
<p>If you’d rather not build everything from scratch, I've got you covered. I’ve published a fully typed, optimized version of the <code>useSearch</code> hook on npm, called <a target="_blank" href="https://www.npmjs.com/package/use-search-react#paginate"><strong>use-search-react</strong></a>. This package not only handles search but also comes with built-in support for sorting, pagination, grouping, and multiple fuzzy search algorithms so you can focus on building your app instead of reinventing the wheel.</p>
<h3 id="heading-how-to-use-it-in-your-component">How to Use it in Your Component</h3>
<h4 id="heading-step-1-install-the-hook">Step 1: Install the hook</h4>
<p>Simply install the package using npm:</p>
<pre><code class="lang-bash">npm install use-search-react
</code></pre>
<h4 id="heading-step-2-import-and-use-the-hook">Step 2: Import and use the hook</h4>
<p>Using the hook in your component is straightforward. For example, consider the following component that uses the hook to perform a fuzzy search on an array of data:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useSearch, search } <span class="hljs-keyword">from</span> <span class="hljs-string">"use-search-react"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SearchComponent</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [query, setQuery] = useState(<span class="hljs-string">""</span>);

    <span class="hljs-keyword">const</span> data = [
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"JavaScript"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Python"</span> },
        { <span class="hljs-attr">name</span>: <span class="hljs-string">"Java"</span> }
    ];

    <span class="hljs-comment">// The 'search' function here is configured to perform a fuzzy search.</span>
    <span class="hljs-keyword">const</span> results = useSearch(
        data,
        query,
        search({
            <span class="hljs-attr">fields</span>: [<span class="hljs-string">"name"</span>],
            <span class="hljs-attr">matchType</span>: <span class="hljs-string">"fuzzy"</span>,
        })
    );

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{query}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setQuery(e.target.value)}
                placeholder="Search..."
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span>&gt;</span>
                {results.map((item, index) =&gt; (
                    <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>&gt;</span>{item.name}<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                ))}
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}
</code></pre>
<p>This example shows how easy it is to use the hook in your React component. The package is built to handle even very large datasets—tens of thousands of records—while keeping your application responsive and efficient.</p>
<p>Here is an example of it working with ten thousand records of data</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/xbKeZYg" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>For more detailed usage and additional configuration options (like pagination, sorting, or grouping), check out the full documentation on npm: <a target="_blank" href="https://www.npmjs.com/package/use-search-react">use-search-react Docs</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Building a search system in React is more than just filtering data. It's about crafting an experience that feels intuitive and responsive for your users.</p>
<p>In this article, you learned how to build a custom <code>useSearch</code> hook that can address common challenges like performance issues, handling nested data, and even forgiving user typos with fuzzy search. We also looked at how to use pagination to manage large datasets.</p>
<p>Whether you decide to build your own from scratch or use the fully typed, ready-made version available on npm, you now have the search functionality that you can easily drop in any of your React projects.</p>
<p>Take these ideas, experiment with them, and adjust the implementation to fit your specific needs.</p>
<p>If you have any questions, feel free to find me on Twitter at <a target="_blank" href="https://x.com/sprucekhalifa">@sprucekhalifa</a>, and don’t forget to follow me for more tips and updates. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Classes in JavaScript – A Handbook for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ Are you curious about classes in JavaScript but feel a little puzzled about how they work or why you'd even use them? If that's you, then you're definitely in the right place. Lots of developers find classes a bit tricky at first, and honestly, I was... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-classes-in-javascript-handbook/</link>
                <guid isPermaLink="false">67b47d2761b19f350f00901b</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Object Oriented Programming ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Tue, 18 Feb 2025 12:29:27 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739878241514/a725b4af-8061-49c2-9575-2aa4096acb74.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Are you curious about classes in JavaScript but feel a little puzzled about how they work or why you'd even use them? If that's you, then you're definitely in the right place. Lots of developers find classes a bit tricky at first, and honestly, I was once there too.</p>
<p>This article is for you if any of these sounds familiar:</p>
<ul>
<li><p>JavaScript is your first programming language.</p>
</li>
<li><p>You are new to, or not entirely comfortable with, Object-Oriented Programming (OOP) principles.</p>
</li>
<li><p>You have primarily used functions for structuring your JavaScript code.</p>
</li>
</ul>
<p>If you're nodding along to any of these, then keep reading.</p>
<p>In this article, we'll take a step-by-step approach, showing you how object-oriented programming is implemented in JavaScript with objects and constructor functions, and clearly illustrate why understanding and using classes will make you a more versatile and effective JavaScript developer, even if you’re used to writing everything in functions. We’ll end everything with a simple to-do app example so you can see how to use classes.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-functions-functions-everywhere-i-turn">Functions, Functions Everywhere I Turn</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-hold-on-a-second-are-we-saying-functions-are-bad-now">Hold on a second. Are we saying functions are bad now?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wait-what-javascript-has-no-real-classes">Wait, what? JavaScript has no real classes?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lets-talk-about-objects-in-javascript">Let's talk about objects in JavaScript.</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-constructor-functions-object-blueprintslets-get-practical">Constructor Functions: Object Blueprints—Let's Get Practical</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-constructor-functions-great-for-blueprints-but-memory-waste">Constructor Functions: Great for Blueprints, but... Memory Waste?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prototypes-to-the-rescue-again-sharing-methods-efficiently">Prototypes to the Rescue (Again): Sharing Methods Efficiently</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-constructor-functions-prototypes-a-powerful-combo">Constructor Functions + Prototypes: A Powerful Combo</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-inheritance-with-constructor-functions-passing-down-the-family-traits-the-constructor-way">Inheritance with Constructor Functions: Passing Down the Family Traits (the Constructor Way)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-enter-es6-classes-syntactic-sugar-for-prototypes">Enter ES6 Classes: Syntactic Sugar for Prototypes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-es6-classes-class-syntax-prototypes-in-disguise">ES6 Classes: Class Syntax – Prototypes in Disguise</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-whats-next-more-class-features-and-real-world-examples">What’s Next? More Class Features and Real-World Examples</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-functions-functions-everywhere-i-turn">Functions, Functions Everywhere I Turn</h2>
<p>If you started with JavaScript, chances are that you've become really comfortable with functions. They're like the building blocks of everything for you, right? Think about it: if I asked you to write a program to greet someone by name, you'd probably whip up something like this in a flash:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">greetUser</span>(<span class="hljs-params">userName</span>) </span>{
  alert(<span class="hljs-string">"Hello, "</span> + userName + <span class="hljs-string">"!"</span>);
}

greetUser(<span class="hljs-string">"Alice"</span>); <span class="hljs-comment">// Like magic! It greets Alice.</span>
</code></pre>
<p>Okay, let's level up a bit. Imagine that I asked you to write a program that figures out someone's birth year just by knowing their age. If they're 25, you'd want it to tell them '2000' (assuming the current year is 2025).</p>
<p>What would your first thought be? Probably something like, 'Function time!' Am I right? You'd think, 'I'll write a function; it'll take the age, and boom, it'll spit out the birth year.' See?</p>
<p>Function-first thinking. Totally natural in JavaScript. And here's how you might code it:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getBirthYear</span>(<span class="hljs-params">age</span>) </span>{
  <span class="hljs-keyword">const</span> currentYear = <span class="hljs-number">2025</span>; <span class="hljs-comment">//  For this example, let's say it's 2025</span>
  <span class="hljs-keyword">const</span> birthYear = currentYear - age;
  <span class="hljs-keyword">return</span> birthYear;
}
<span class="hljs-built_in">console</span>.log(getBirthYear(<span class="hljs-number">25</span>)); <span class="hljs-comment">// Yep, it logs 2000!</span>
</code></pre>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/gbOYvvo" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>Now, let's make it a bit more complex. What if we want to be a little smarter and make sure the age is actually a valid age? You know, not some crazy string or a negative number. Sticking with our function-loving brains, what's the natural next step? Another function, of course. We'd probably create a <code>validateAge</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">validateAge</span>(<span class="hljs-params">age</span>) </span>{
  <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> age !== <span class="hljs-string">"number"</span> || age &lt;= <span class="hljs-number">0</span> || age &gt; <span class="hljs-number">120</span>) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Invalid age"</span>;
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">return</span> age; <span class="hljs-comment">//  Age is good to go!</span>
  }
}

<span class="hljs-built_in">console</span>.log(validateAge(<span class="hljs-number">25</span>)); <span class="hljs-comment">//  Output: 25 (valid!)</span>
<span class="hljs-built_in">console</span>.log(validateAge(<span class="hljs-string">"twenty"</span>)); <span class="hljs-comment">//  Output: Invalid age (not a number)</span>
<span class="hljs-built_in">console</span>.log(validateAge(<span class="hljs-number">-5</span>)); <span class="hljs-comment">//  Output: Invalid age (negative)</span>
</code></pre>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/xbxKYjZ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>See how we're just piling up functions? <code>getBirthYear</code> does one thing, <code>validateAge</code> does another. They're separate little boxes of code.</p>
<p>Let's push this a little further. What if we also wanted to figure out someone's zodiac sign based on their birth year? Yep, you guessed it—the brain says, 'More functions.' Let's just write another <code>getZodiacSign</code> function:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getZodiacSign</span>(<span class="hljs-params">birthYear</span>) </span>{
    <span class="hljs-keyword">const</span> signs = [
        <span class="hljs-string">"Monkey"</span>, 
        <span class="hljs-string">"Rooster"</span>, 
        <span class="hljs-string">"Dog"</span>, 
        <span class="hljs-string">"Pig"</span>, 
        <span class="hljs-string">"Rat"</span>,    
        <span class="hljs-string">"Ox"</span>,
        <span class="hljs-string">"Tiger"</span>, 
        <span class="hljs-string">"Rabbit"</span>, 
        <span class="hljs-string">"Dragon"</span>, 
        <span class="hljs-string">"Snake"</span>, 
        <span class="hljs-string">"Horse"</span>, 
        <span class="hljs-string">"Sheep"</span>
    ];
    <span class="hljs-keyword">return</span> signs[birthYear % <span class="hljs-number">12</span>]; <span class="hljs-comment">// Simple modulo trick!</span>
}
</code></pre>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/RNwbQxg" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>Are you noticing the pattern here? For every new thing we want to do we're just adding more <em>and</em> more separate functions. Things are starting to feel a <em>bit...</em> scattered, right? And we're not even done adding features.</p>
<p>Okay, now let's say we want to store even more information about a person—their name, country, profession, besides just age. How would we manage all this with our function-centric approach? Well, we might try to create a big 'Person' function that takes all this info:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Person</span>(<span class="hljs-params">name, age, country, profession</span>) </span>{
  <span class="hljs-keyword">const</span> personName = name;
  <span class="hljs-keyword">const</span> personAge = age;
  <span class="hljs-keyword">const</span> personCountry = country;
  <span class="hljs-keyword">const</span> personProfession = profession;

  <span class="hljs-keyword">const</span> validatedAge = validateAge(personAge);
  <span class="hljs-keyword">const</span> birthYear = getBirthYear(validatedAge);
  <span class="hljs-keyword">const</span> zodiacSign = getZodiacSign(birthYear);

  alert(
    <span class="hljs-string">`<span class="hljs-subst">${personName}</span>, you're <span class="hljs-subst">${personAge}</span> years old, born in <span class="hljs-subst">${birthYear}</span>, zodiac sign: <span class="hljs-subst">${zodiacSign}</span>!`</span>
  );
}
</code></pre>
<p>What if we then want to use the person's name in our other functions, like <code>getZodiacSign</code> or <code>getBirthYear</code>? We'd have to go back and manually add <code>name</code> as an argument to each of those functions. Imagine having to update every function whenever you add a new piece of person information.</p>
<pre><code class="lang-js"><span class="hljs-comment">//  Suddenly, we need 'name' everywhere!</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getZodiacSign</span>(<span class="hljs-params">birthYear, name</span>) </span>{
  alert(<span class="hljs-string">"Zodiac sign for "</span> + name + <span class="hljs-string">" is..."</span>);
  <span class="hljs-comment">//... rest of zodiac logic...</span>
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getBirthYear</span>(<span class="hljs-params">age, name</span>) </span>{
  alert(<span class="hljs-string">"Birth year for "</span> + name + <span class="hljs-string">" is..."</span>);
  <span class="hljs-comment">// ... rest of birth year logic...</span>
}
</code></pre>
<p>In this tiny example, it's sort of manageable. But picture a huge project with tons of functions spread across files and folders, how you’d try to keep everything in sync and update functions whenever your <code>person</code> data changes. That sounds like a recipe for headaches, bugs, and a lot of frustration. It can become incredibly inefficient and, honestly, pretty error-prone.</p>
<h2 id="heading-hold-on-a-second-are-we-saying-functions-are-bad-now">Hold on a second. Are we saying functions are bad now?</h2>
<p>Functions are amazing. Think of this function-focused approach as the 'classic JavaScript way' of doing things. If you started with JavaScript, this probably feels totally natural and comfortable—and that's great. Even super popular modern libraries like React are built using functions for components. Functions are incredibly powerful and flexible.</p>
<p>But, even in React, if you change some core data (like a 'prop' in React terms) in a main component, you might have to go digging through lots of other components to make sure everything still works smoothly. Functions are fantastic, but sometimes, for certain kinds of problems, there might be another way to organize our code. A way that, for some folks, feels more intuitive, especially if they come from other programming backgrounds.</p>
<p>Imagine asking a programmer whose first language was Java or C++ to build our <code>birth year</code> program. Their brain might light up, but they'd probably think something a bit different. Maybe something like this:</p>
<p>'We need a <code>Person(class)</code>. A <code>Person</code> has an <code>age(proterty)</code> and we need a way to <code>calculateBirthYear(action)</code> for a <code>Person</code>.'</p>
<p>Notice anything different? Functions aren't the first thing that jumps to their mind. It's more about <code>objects</code> and <code>things</code> having <code>properties</code> and <code>actions</code>. Mind-blowing, huh? Many programmers who started with languages like Java or C++ naturally think in this object-oriented (or OOP) style. And hey, maybe that's why you're reading this—maybe you're curious about exploring this object-thinking approach too, especially in JavaScript. Don't worry, I’m not asking you to suddenly switch to Java 😉.</p>
<p>So, about these classes in JavaScript. Get ready for a little JavaScript twist. Here's the thing: JavaScript technically doesn't have classes in the way languages like Java or C++ do. I know, it can be a bit of a head-scratcher. Instead of classical classes as found in languages like Java or C++, JavaScript is built on something called prototypes*.* It uses these flexible prototypes and objects to mimic how classes work in other languages. So, if you want to use classes in JavaScript effectively, the real key is to understand objects and prototypes first. That's where the magic is in JavaScript OOP.</p>
<h2 id="heading-wait-what-javascript-has-no-real-classes">Wait, what? JavaScript has no real classes?</h2>
<p>Does that mean we are stuck with just functions forever? Nope. Even though JavaScript does things its own way with prototypes (instead of classic classes), it still fully supports 'Object-Oriented Programming' (OOP).</p>
<p>Let's break down OOP in plain English. Two big ideas in OOP are <strong>Encapsulation</strong> and <strong>Inheritance</strong>. Sounds fancy, right? But they're actually pretty simple concepts.</p>
<p>Encapsulation? Imagine a capsule, like for medicine. You're just bundling things that belong together. In OOP, encapsulation means grouping data (like age, name) and the actions you can do with that data (like calculate birth year, greet) inside a single 'object'. JavaScript objects are perfect for this.</p>
<p>And inheritance? Think of it like inheriting traits from your family. In JavaScript OOP, objects can 'inherit' properties and behaviors from other objects. JavaScript calls this prototypal inheritance, and the object you inherit from is called the prototype (we'll dive deeper into prototype soon).</p>
<p>See? No function jail here. JavaScript is totally ready for OOP. To see this in action, let's rewrite our birth year program, but this time using this OOP style in JavaScript.</p>
<p>Check this out. Here's how we could rewrite our birth year program using an OOP style in JavaScript, using just a good old JavaScript object:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Person = {
  <span class="hljs-comment">//  --- Properties (Data) ---</span>
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Spruce"</span>,
  <span class="hljs-attr">age</span>: <span class="hljs-number">25</span>,
  <span class="hljs-attr">country</span>: <span class="hljs-string">"Nigeria"</span>,
  <span class="hljs-attr">profession</span>: <span class="hljs-string">"Engineer"</span>,

  <span class="hljs-comment">//  --- Methods (Actions related to Person data) ---</span>
  <span class="hljs-attr">isValidAge</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">typeof</span> <span class="hljs-built_in">this</span>.age === <span class="hljs-string">"number"</span> &amp;&amp; <span class="hljs-built_in">this</span>.age &gt; <span class="hljs-number">0</span>;
  },

  <span class="hljs-attr">getBirthYear</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.isValidAge()) {
      <span class="hljs-keyword">return</span> <span class="hljs-string">"Invalid age!"</span>;
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getFullYear() - <span class="hljs-built_in">this</span>.age;
  },

  <span class="hljs-attr">getZodiacSign</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> (!<span class="hljs-built_in">this</span>.isValidAge()) {
      <span class="hljs-keyword">return</span> <span class="hljs-string">"Oops, can't get zodiac for an invalid age!"</span>;
    }

    <span class="hljs-keyword">const</span> birthYear = <span class="hljs-built_in">this</span>.getBirthYear();
    <span class="hljs-keyword">const</span> zodiacSigns = [
      <span class="hljs-string">"Capricorn"</span>,
      <span class="hljs-string">"Aquarius"</span>,
      <span class="hljs-string">"Pisces"</span>,
      <span class="hljs-string">"Aries"</span>,
      <span class="hljs-string">"Taurus"</span>,
      <span class="hljs-string">"Gemini"</span>,
      <span class="hljs-string">"Cancer"</span>,
      <span class="hljs-string">"Leo"</span>,
      <span class="hljs-string">"Virgo"</span>,
      <span class="hljs-string">"Libra"</span>,
      <span class="hljs-string">"Scorpio"</span>,
      <span class="hljs-string">"Sagittarius"</span>,
    ];
    <span class="hljs-keyword">return</span> zodiacSigns[birthYear % <span class="hljs-number">12</span>];
  },

  <span class="hljs-attr">greet</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> (
      <span class="hljs-string">`Hello, I'm <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>. I'm <span class="hljs-subst">${
        <span class="hljs-built_in">this</span>.age
      }</span> years old, born in <span class="hljs-subst">${<span class="hljs-built_in">this</span>.getBirthYear()}</span>, `</span> +
      <span class="hljs-string">`working as a <span class="hljs-subst">${<span class="hljs-built_in">this</span>.profession}</span> from <span class="hljs-subst">${
        <span class="hljs-built_in">this</span>.country
      }</span>.  My zodiac sign is <span class="hljs-subst">${<span class="hljs-built_in">this</span>.getZodiacSign()}</span>.`</span>
    );
  },
};

<span class="hljs-comment">//  --- Let's use our Person object! ---</span>
<span class="hljs-built_in">console</span>.log(Person.greet());
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-comment">//  Output (might vary slightly depending on year):</span>

<span class="hljs-comment">// "Hello, I'm Spruce. I'm 25 years old, born in 2000, working as a Engineer from Nigeria.  My zodiac sign is Pig."</span>
</code></pre>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/mydbXKq" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>See how neat that is? Everything about a <code>Person</code>, their details (name, age, and so on) and what you can do with a person (validate age, get birth year, greet) is all bundled together, and nicely organized inside this single <code>Person</code> object. That's encapsulation in action. Pretty cool, right?</p>
<p>Now, want to know the <code>Person</code> name? Super easy:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(Person.name); <span class="hljs-comment">// Output: "Spruce"</span>
</code></pre>
<p>Birth year? Piece of cake:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(Person.getBirthYear()); <span class="hljs-comment">// Output (if current year is 2025): 2000</span>
</code></pre>
<p>And here's the real magic of encapsulation: if we change something inside the <code>Person</code> object (like, say, we decide to change the age), all the methods (actions) inside automatically adapt. We don't have to go hunting around in separate functions to update things. Let me show you:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//  Age is 25 initially...</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Birth year when age is 25:"</span>, Person.getBirthYear()); <span class="hljs-comment">// Output (if current year is 2025): 2000</span>

<span class="hljs-comment">//  Let's update the age directly in the Person object...</span>
Person.age = <span class="hljs-number">30</span>;

<span class="hljs-comment">//  Now, getBirthYear automatically uses the *new* age!</span>
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Birth year when age is 30:"</span>, Person.getBirthYear()); <span class="hljs-comment">// Output (if current year is 2025): 1995</span>
</code></pre>
<p>So, JavaScript uses objects—and, as we'll see, prototypes—to bring OOP to life, even if it doesn't have classic classes. Hopefully, you're starting to see the appeal of organizing code this way. Before we jump into classes, it makes a ton of sense to get a really solid understanding of objects and prototypes in JavaScript, right? That's what we'll dive into next.</p>
<h2 id="heading-lets-talk-about-objects-in-javascript">Let's talk about objects in JavaScript.</h2>
<p>If you're already familiar with how objects work, that's fantastic. It'll make understanding everything we cover in this article even smoother. To make sure we're all on the same page, let's start with a super basic object:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Person = {};
</code></pre>
<p>So, is <code>Person</code> an empty object? At first glance, it certainly looks empty. If you thought "yes," you're not alone. It's a common initial thought. But in JavaScript, objects are a little more interesting than just what we explicitly put into them. Let's explore how objects really work under the hood.</p>
<h3 id="heading-okay-so-how-do-objects-work-in-javascript">Okay, so how do objects work in JavaScript?</h3>
<p>Let's break it down. At its core, an object is a collection of properties. Think of properties as named containers for values. Each property has a name (also called a 'key').</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Person = {
  <span class="hljs-attr">firstName</span>: <span class="hljs-string">"John"</span>,
  <span class="hljs-attr">lastName</span>: <span class="hljs-string">"Doe"</span>,
};
</code></pre>
<p><code>firstName</code> and <code>lastName</code> are the property names (keys), and <code>"John"</code> and <code>"Doe"</code> are their respective values. A property in an object is always a key-value pair. The value part can be many things.</p>
<p>The value associated with a property can be a primitive data type. In JavaScript, primitives are things like strings, numbers, booleans (<code>true</code> or <code>false</code>), <code>null</code>, <code>undefined</code>, and symbols. Let's see some examples:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> exampleObject = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Example"</span>, <span class="hljs-comment">// String</span>
  <span class="hljs-attr">age</span>: <span class="hljs-number">30</span>, <span class="hljs-comment">// Number</span>
  <span class="hljs-attr">isStudent</span>: <span class="hljs-literal">false</span>, <span class="hljs-comment">// Boolean</span>
  <span class="hljs-attr">favoriteColor</span>: <span class="hljs-literal">null</span>, <span class="hljs-comment">// null</span>
};
</code></pre>
<p>But the cool thing is, property values can also be more complex data types or even other objects, functions, and arrays. Let's look at that:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> anotherObject = {
  <span class="hljs-attr">address</span>: {
    <span class="hljs-comment">// Value is another object</span>
    <span class="hljs-attr">street</span>: <span class="hljs-string">"123 Main St"</span>,
    <span class="hljs-attr">city</span>: <span class="hljs-string">"Anytown"</span>,
  },
  <span class="hljs-attr">hobbies</span>: [<span class="hljs-string">"reading"</span>, <span class="hljs-string">"hiking"</span>], <span class="hljs-comment">// Value is an array</span>
  <span class="hljs-attr">greet</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Value is a function (a method!)</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Hello!"</span>);
  },
};
</code></pre>
<p>When a function is a property of an object, we call it a method. It's essentially a function that belongs to the object and usually operates on the object's data.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> calculator = {
  <span class="hljs-attr">value</span>: <span class="hljs-number">0</span>,
  <span class="hljs-attr">add</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">number</span>) </span>{
    <span class="hljs-built_in">this</span>.value += number; <span class="hljs-comment">// 'this' refers to the calculator object</span>
  },
  <span class="hljs-attr">getValue</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.value;
  }
};

calculator.add(<span class="hljs-number">5</span>);
<span class="hljs-built_in">console</span>.log(calculator.getValue()); <span class="hljs-comment">// Output: 5</span>
</code></pre>
<p>Now, here’s where things get really interesting. Objects in JavaScript don't just have the properties we explicitly define. They can also reference properties from other objects. This is a core concept called prototypal inheritance (sometimes just called prototypal delegation).</p>
<p>Remember our seemingly empty <code>Person = {}</code> object? We said it looked empty, right? Well, it's time for a bit of JavaScript magic. Even though we didn't put any properties in it ourselves, it's not completely empty. Every object in JavaScript, by default, has a hidden link (often referred to internally as its [[Prototype]] property) to another object called its prototype.</p>
<p>For objects created using the simple <code>{}</code> syntax (like our <code>person</code> object), their default prototype is the built-in <code>Object.prototype</code>. Think of <code>Object.prototype</code> as a kind of parent object that provides some basic, built-in functionality to all objects.</p>
<p>This is why you can do things like this, even with our "empty" <code>Person</code> object:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(Person.toString()); <span class="hljs-comment">// Output: [object Object]</span>
</code></pre>
<p>Wait a minute. We never defined a <code>toString()</code> method in our <code>Person</code> object. So where is it coming from? It's coming from its prototype, <code>Object.prototype</code>. <code>toString()</code> is a method that's built into <code>Object.prototype</code>, and because <code>Person's</code> prototype is <code>Object.prototype</code>, <code>Person</code> can access and use the <code>toString()</code> method.</p>
<p>So, a good way to think about it is: "The prototype of an object is another object from which it can look up and use properties and methods if it doesn't have them itself."</p>
<p>Why is understanding prototypes so important? Because it unlocks the power of code reuse and creating specialized objects based on more general ones. This is where things get really powerful, especially as your JavaScript projects grow.</p>
<p>Imagine that we want to create a more specific type of <code>Person</code>—say, a <code>Developer</code>. A <code>Developer</code> is still a <code>Person</code>, but they might have some additional properties or behaviors specific to developers. Basically, we want a <code>Developer</code> object to be a <code>Person</code>, but also have its own unique stuff.</p>
<p>This is where we can explicitly set up prototypes. Instead of relying on the default <code>Object.prototype</code>, we can tell JavaScript: "Hey, I want the prototype of my <code>Developer</code> object to be the <code>Person</code> object we already defined." We can do this using <code>Object.create()</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> Person = {
  <span class="hljs-attr">firstName</span>: <span class="hljs-string">"John"</span>,
  <span class="hljs-attr">lastName</span>: <span class="hljs-string">"Doe"</span>,
  <span class="hljs-attr">sayHello</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, my name is <span class="hljs-subst">${<span class="hljs-built_in">this</span>.firstName}</span> <span class="hljs-subst">${<span class="hljs-built_in">this</span>.lastName}</span>`</span>);
  },
};

<span class="hljs-keyword">const</span> developer = <span class="hljs-built_in">Object</span>.create(Person); <span class="hljs-comment">// developer's prototype is now 'Person'</span>
developer.firstName = <span class="hljs-string">"Spruce"</span>; <span class="hljs-comment">// Add a *specific* firstName for developer</span>
developer.programmingLanguage = <span class="hljs-string">"JavaScript"</span>; <span class="hljs-comment">// Developer's own property</span>

developer.sayHello(); <span class="hljs-comment">// Output: Hello, my name is Spruce Person (still accesses sayHello from 'person' prototype!)</span>
<span class="hljs-built_in">console</span>.log(developer.programmingLanguage); <span class="hljs-comment">// Output: JavaScript (developer's own property)</span>
<span class="hljs-built_in">console</span>.log(developer.lastName); <span class="hljs-comment">// Output: Doe (inherited from 'Person' prototype!)</span>
</code></pre>
<p>Let's break down what's happening when we access properties on <code>Developer</code>:"</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">console</span>.log(developer.firstName); <span class="hljs-comment">// Output: Spruce (developer's *own* property)</span>
<span class="hljs-built_in">console</span>.log(developer.programmingLanguage); <span class="hljs-comment">// Output: JavaScript (developer's *own* property)</span>
<span class="hljs-built_in">console</span>.log(developer.lastName); <span class="hljs-comment">// Output: Doe (found on the *prototype* 'Person')</span>
<span class="hljs-built_in">console</span>.log(developer.sayHello()); <span class="hljs-comment">// Output: Hello, my name is Spruce Person (method from *prototype*)</span>
<span class="hljs-built_in">console</span>.log(developer.job); <span class="hljs-comment">// Output: undefined (not on 'Developer' OR 'Person' prototype)</span>
</code></pre>
<p>When you try to access a property like <code>Developer.lastName</code>, JavaScript does the following:</p>
<ol>
<li><p>First, it checks: Does <code>Developer</code> have a property named <code>lastName</code> directly on itself? In our example, <code>Developer</code> only has <code>firstName</code> and <code>programmingLanguage</code> as its own properties. <code>lastName</code> is not there.</p>
</li>
<li><p>If it doesn't find it on the object itself, JavaScript then looks at the object's prototype (which we set to <code>Person using</code> <code>Object.create()</code>).</p>
</li>
<li><p>It checks: 'Does the <code>Person</code> object (the prototype) have a property named <code>lastName</code>?' Yes, <code>Person</code> does have <code>lastName: "Doe"</code>. So, JavaScript uses this value.</p>
</li>
<li><p>If the property isn’t found on the prototype either, JavaScript would then look at the <code>Person</code>'s prototype (which is <code>Object.prototype</code> by default), and so on, up the prototype chain. If it goes all the way up the chain and still doesn't find the property, it finally returns <code>undefined</code> (like when we tried to access <code>developer.job</code>).</p>
</li>
</ol>
<p>Own properties are simply the properties that are defined directly on the object itself when you create it (like <code>firstName</code> and <code>programmingLanguage</code> on <code>Developer</code>). Prototype properties are accessed through the prototype chain.</p>
<p>You can even create longer prototype chains. For example, let's say we want to create a <code>JavaScriptDeveloper</code> object, which is a type of <code>Developer</code>. We can make <code>Developer</code> the prototype of <code>JavaScriptDeveloper</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> JavaScriptDeveloper = <span class="hljs-built_in">Object</span>.create(Developer); <span class="hljs-comment">// javaScriptDeveloper's prototype is 'Developer'</span>

JavaScriptDeveloper.framework = <span class="hljs-string">"React"</span>; <span class="hljs-comment">// JavaScriptDeveloper's own property</span>

<span class="hljs-built_in">console</span>.log(JavaScriptDeveloper.firstName); <span class="hljs-comment">// Output: Spruce (from 'Developer' prototype)</span>

<span class="hljs-built_in">console</span>.log(JavaScriptDeveloper.lastName); <span class="hljs-comment">// Output: Doe (from 'Person' prototype)</span>

<span class="hljs-built_in">console</span>.log(JavaScriptDeveloper.programmingLanguage); <span class="hljs-comment">// Output: JavaScript (from 'Developer' prototype)</span>

<span class="hljs-built_in">console</span>.log(JavaScriptDeveloper.framework); <span class="hljs-comment">// Output: React (JavaScriptDeveloper's own property)</span>

<span class="hljs-built_in">console</span>.log(JavaScriptDeveloper.job); <span class="hljs-comment">// Output: undefined (not found anywhere in the chain)</span>
</code></pre>
<p>(Optional Exploration: If you're curious, trace the lookup for <code>javaScriptDeveloper.lastName</code>. It goes: <code>JavaScriptDeveloper</code> -&gt; <code>Developer</code> -&gt; <code>Person</code> -&gt; <code>Object.prototype</code>).</p>
<p>Okay, prototypes are powerful. We can create objects that share properties and behaviors and specialize them for different needs. But imagine if we wanted to create hundreds of <code>Person</code> objects, hundreds of <code>Developer</code> objects, and hundreds of <code>JavaScriptDeveloper</code> objects.</p>
<p>Using <code>Object.create()</code> every time would still be quite repetitive, especially if we want to ensure that every <code>Person</code> starts with the same basic properties (like <code>firstName</code> and <code>lastName</code>).</p>
<p>We need a better way to create multiple objects that follow the same pattern, like a blueprint that we can re-use over and over again to create objects. This is what classes are for, they are just blueprints that we can use to create multiple objects, and JavaScript uses Constructor functions to create classes (the blueprints).</p>
<p>In the next section, we’ll dive into how javascript uses Constructor functions to implement classes.</p>
<h2 id="heading-constructor-functions-object-blueprintslets-get-practical">Constructor Functions: Object Blueprints—Let's Get Practical</h2>
<p>Okay, prototypes are pretty cool for code reuse and making specialized objects. We saw how <code>Object.create()</code> lets us create objects that inherit from others. But imagine that we wanted to make tons of <code>Person</code> objects, like, hundreds of them for a website. Typing out <code>Object.create(person)</code> for every single one would get super repetitive, especially if we always want every <code>Person</code> to start with the same basic properties, like a <code>firstName</code> and <code>lastName</code>.</p>
<p>We need a more efficient way to make lots of objects that follow the same pattern. What we really need is something like a blueprint—something we can use over and over again to stamp out new objects, all looking and working in a similar way. And guess what? That’s exactly what constructor functions are for.</p>
<p>Think of constructor functions as JavaScript's way of creating blueprints for objects. They're like object factories. And in JavaScript, we use constructor functions, which are specialized functions used in a particular way, to create these blueprints. Yep, functions again. But we use them in a special way.</p>
<h3 id="heading-so-what-is-a-constructor-function-exactly">So what is a constructor function, exactly?</h3>
<p>Well, like I said, it's a function that creates objects. Take a look at this example:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PersonConstructor</span>(<span class="hljs-params">name, age</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name;
  <span class="hljs-built_in">this</span>.age = age;
  <span class="hljs-built_in">this</span>.greet = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, I'm <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>);
  };
}
</code></pre>
<p>That looks like a regular function. You're absolutely right. It looks just like any other function you've probably written in JavaScript. In fact, let's prove it. If we just log <code>PersonConstructor</code> itself, we’ll see:</p>
<pre><code class="lang-js"><span class="hljs-built_in">console</span>.log(PersonConstructor);
</code></pre>
<pre><code class="lang-js"><span class="hljs-comment">// output</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PersonConstructor</span>(<span class="hljs-params">name, age</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name;
  <span class="hljs-built_in">this</span>.age = age;
  <span class="hljs-built_in">this</span>.greet = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, I'm <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>);
  };
}
</code></pre>
<p>See? Just a regular function. So, what makes it a constructor function?</p>
<h3 id="heading-the-magic-ingredient-the-new-keyword">The Magic Ingredient: The <code>new</code> Keyword</h3>
<p>What turns an ordinary function into a constructor**—**something that builds objects—is the <code>new</code> keyword. It's like saying to JavaScript, "Hey, treat this function as a blueprint, and use it to create a new object for me."</p>
<p>Let's see it in action:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> PersonConstructor(<span class="hljs-string">"Alice"</span>, <span class="hljs-number">25</span>);

<span class="hljs-built_in">console</span>.log(person1);
</code></pre>
<pre><code class="lang-js"><span class="hljs-comment">// output</span>

<span class="hljs-comment">// PersonConstructor { name: 'Alice', age: 25, greet: [Function] }</span>
</code></pre>
<p>In the output now, instead of just seeing the function code, we're seeing a <code>PersonConstructor</code> object. The <code>new</code> keyword didn't just call the function, it actually created a brand new object based on the <code>PersonConstructor</code> blueprint.</p>
<p>Now, we can use this blueprint, <code>PersonConstructor</code>, to create as many <code>Person</code> objects as we want, all with the same basic structure:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> PersonConstructor(<span class="hljs-string">"Alice"</span>, <span class="hljs-number">25</span>);
<span class="hljs-keyword">const</span> person2 = <span class="hljs-keyword">new</span> PersonConstructor(<span class="hljs-string">"Bob"</span>, <span class="hljs-number">30</span>);
<span class="hljs-keyword">const</span> person3 = <span class="hljs-keyword">new</span> PersonConstructor(<span class="hljs-string">"Charlie"</span>, <span class="hljs-number">28</span>);

<span class="hljs-built_in">console</span>.log(person1);
<span class="hljs-built_in">console</span>.log(person2);
<span class="hljs-built_in">console</span>.log(person3);
</code></pre>
<pre><code class="lang-js"><span class="hljs-comment">// output</span>
PersonConstructor { <span class="hljs-attr">name</span>: <span class="hljs-string">'Alice'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span>, <span class="hljs-attr">greet</span>: [<span class="hljs-built_in">Function</span>] }
PersonConstructor { <span class="hljs-attr">name</span>: <span class="hljs-string">'Bob'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">30</span>, <span class="hljs-attr">greet</span>: [<span class="hljs-built_in">Function</span>] }
PersonConstructor { <span class="hljs-attr">name</span>: <span class="hljs-string">'Charlie'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">28</span>, <span class="hljs-attr">greet</span>: [<span class="hljs-built_in">Function</span>] }
</code></pre>
<p>Cool, right? We have three distinct <code>Person</code> objects, all created from the same <code>PersonConstructor</code> blueprint.</p>
<h3 id="heading-hold-up-whats-this-this-keyword-i-keep-seeing">Hold Up... What's This <code>this</code> Keyword I Keep Seeing?</h3>
<p>You've probably noticed the word <code>this</code> popping up a lot in these code examples, like in <code>this.name</code>, <code>this.age</code>, and <code>this.greet()</code>. And you might be thinking, "What in the JavaScript world is <code>this</code>?"</p>
<p>Don't worry, <code>this</code> can be a bit confusing at first, but it's actually pretty simple once you get the hang of it. Let's break it down with a simple analogy.</p>
<p>Imagine you're describing yourself. You might say, "My name is [Your Name]." In this sentence, "my" refers to you, the person speaking.</p>
<p>In JavaScript objects, <code>this</code> is like "my" or "me." It's a way for an object to refer to itself.</p>
<p>Let's see this with a regular object example first:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> PersonObject = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Spruce"</span>,
  <span class="hljs-attr">greet</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Hello, my name is "</span> + PersonObject.name); <span class="hljs-comment">//  Using PersonObject.name directly</span>
  },
};

PersonObject.greet(); <span class="hljs-comment">// Output: Hello, my name is Spruce</span>
</code></pre>
<p>In this <code>PersonObject</code>, inside the <code>greet</code> function, we used <code>PersonObject.name</code> to access the <code>name</code> property. This works perfectly fine. We're directly telling JavaScript to get the <code>name</code> property from the <code>PersonObject</code>. We could use <code>this</code> here too, but let's see why <code>this</code> becomes super helpful, especially in constructor functions.</p>
<p>Now, consider this slightly different version using <code>this</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> PersonObjectThis = {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Spruce"</span>,
  <span class="hljs-attr">greet</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Hello, my name is "</span> + <span class="hljs-built_in">this</span>.name); <span class="hljs-comment">// Using 'this.name'</span>
  },
};

PersonObjectThis.greet(); <span class="hljs-comment">// Output: Hello, my name is Spruce</span>
</code></pre>
<p>See? It still works the same way. When <code>greet</code> is called on <code>PersonObjectThis</code>, inside the <code>greet</code> function, it automatically refers to <code>PersonObjectThis</code>. So <code>this.name</code> is just a more dynamic way of saying "the <code>name</code> property of this current object."</p>
<h3 id="heading-why-use-this-instead-of-directly-naming-the-object">Why use <code>this</code> instead of directly naming the object?</h3>
<p>Because <code>this</code> is dynamic and context-aware. It always points to the object that is currently calling the method. This becomes essential in constructor functions because constructor functions are designed to create many different objects.</p>
<h3 id="heading-back-to-constructor-functions-what-does-this-mean-there">Back to constructor functions: What does <code>this</code> mean there?</h3>
<p>Let's revisit our <code>PersonConstructor</code>:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PersonConstructor</span>(<span class="hljs-params">name, age</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name;
  <span class="hljs-built_in">this</span>.age = age;
  <span class="hljs-built_in">this</span>.greet = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, I'm <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>);
  };
}

<span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> PersonConstructor(<span class="hljs-string">"Alice"</span>, <span class="hljs-number">25</span>);
<span class="hljs-keyword">const</span> person2 = <span class="hljs-keyword">new</span> PersonConstructor(<span class="hljs-string">"Bob"</span>, <span class="hljs-number">30</span>);
</code></pre>
<p>When we do <code>const person1 = new PersonConstructor("Alice", 25);</code> inside the <code>PersonConstructor</code> function:</p>
<ul>
<li><p><code>this</code> becomes <code>person1</code>. It's as if JavaScript is doing:</p>
<ul>
<li><p><a target="_blank" href="http://person1.name"><code>person1.name</code></a> <code>= "Alice";</code></p>
</li>
<li><p><code>person1.age = 25;</code></p>
</li>
<li><p><code>person1.greet = function() { ... };</code></p>
</li>
</ul>
</li>
</ul>
<p>And when we do <code>const person2 = new PersonConstructor("Bob", 30);</code> inside <code>PersonConstructor</code> again:</p>
<ul>
<li><p><code>this</code> becomes <code>person2</code>. Like JavaScript doing:</p>
<ul>
<li><p><a target="_blank" href="http://person2.name"><code>person2.name</code></a> <code>= "Bob";</code></p>
</li>
<li><p><code>person2.age = 30;</code></p>
</li>
<li><p><code>person2.greet = function() { ... };</code></p>
</li>
</ul>
</li>
</ul>
<p>So, <code>this</code> in a constructor function is like a placeholder that gets filled in with the specific object being created when you use <code>new</code>. It's what lets us create many different objects from the same blueprint.</p>
<h2 id="heading-constructor-functions-great-for-blueprints-but-memory-waste">Constructor Functions: Great for Blueprints, but... Memory Waste?</h2>
<p>Okay, so now that you know how to create object blueprints using constructor functions, and you understand what <code>this</code> does, we can make lots of <code>Person</code> objects.</p>
<p>But there's a little problem lurking in our <code>PersonConstructor</code>:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PersonConstructor</span>(<span class="hljs-params">name, age</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name;
  <span class="hljs-built_in">this</span>.age = age;
  <span class="hljs-built_in">this</span>.greet = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// 😬 Look at this greet function!</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, I'm <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>);
  };
}

<span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> PersonConstructor(<span class="hljs-string">"Alice"</span>, <span class="hljs-number">25</span>);
<span class="hljs-keyword">const</span> person2 = <span class="hljs-keyword">new</span> PersonConstructor(<span class="hljs-string">"Bob"</span>, <span class="hljs-number">30</span>);

<span class="hljs-built_in">console</span>.log(person1, person2);
</code></pre>
<pre><code class="lang-js"><span class="hljs-comment">// output</span>

PersonConstructor {<span class="hljs-attr">name</span>: <span class="hljs-string">"Alice"</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">25</span>, <span class="hljs-attr">greet</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>}

<span class="hljs-title">PersonConstructor</span> </span>{name: <span class="hljs-string">"Bob"</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">30</span>, <span class="hljs-attr">greet</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>}</span>
</code></pre>
<p>Notice the <code>greet</code> function inside the <code>PersonConstructor</code>? Every time we create a new <code>Person</code> object using <code>new PersonConstructor()</code>, we're actually copying the entire <code>greet</code> function to each and every object.</p>
<p>Imagine that we create one thousand <code>Person</code> objects. We'd have a thousand identical <code>greet</code> functions in memory. For a simple <code>greet()</code> function, the memory impact might seem small. However, if you had more complex methods with lots of code, or if you were creating thousands or even millions of objects, duplicating these functions for every single object can become a significant waste of memory.</p>
<p>It also impacts performance as JavaScript has to manage all these duplicated functions. That's a lot of duplicated code, and it's not very memory-efficient, especially if the <code>greet</code> function (or other methods) were more complex.</p>
<h2 id="heading-prototypes-to-the-rescue-again-sharing-methods-efficiently">Prototypes to the Rescue (Again): Sharing Methods Efficiently</h2>
<p>Remember prototypes? We learned that objects can inherit properties and methods from their prototypes. Well, constructor functions have a built-in way to use prototypes to solve this memory-waste problem.</p>
<p>Instead of defining the <code>greet</code> function inside the constructor and thus copying it to every instance, we can add it to the <code>prototype</code> of the <code>PersonConstructor</code> function.</p>
<p>Like this:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PersonConstructor</span>(<span class="hljs-params">name, age</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name;
  <span class="hljs-built_in">this</span>.age = age;
}

<span class="hljs-comment">//  --- Add the greet method to the PROTOTYPE of PersonConstructor! ---</span>
PersonConstructor.prototype.greet = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, I'm <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>);
};
</code></pre>
<p>Now, the <code>greet</code> method is defined only once on <code>PersonConstructor.prototype</code>. But all objects created with <code>PersonConstructor</code> can still use it. They inherit it from the prototype.</p>
<p>Let's test it:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> person1 = <span class="hljs-keyword">new</span> PersonConstructor(<span class="hljs-string">"Alice"</span>, <span class="hljs-number">25</span>);
<span class="hljs-keyword">const</span> person2 = <span class="hljs-keyword">new</span> PersonConstructor(<span class="hljs-string">"Bob"</span>, <span class="hljs-number">30</span>);

person1.greet(); <span class="hljs-comment">// Output: Hello, I'm Alice  - Still works!</span>
person2.greet(); <span class="hljs-comment">// Output: Hello, I'm Bob    - Still works!</span>

<span class="hljs-built_in">console</span>.log(person1.greet === person2.greet); <span class="hljs-comment">// Output: false - They are NOT the same function object in memory</span>

<span class="hljs-built_in">console</span>.log(person1.__proto__.greet === person2.__proto__.greet); <span class="hljs-comment">// Output: true - But they share the same prototype method!</span>
</code></pre>
<p><code>person1.greet()</code> and <code>person2.greet()</code> still work perfectly. But now, the <code>greet</code> function is not copied for each object. It's shared through the prototype. This is much more efficient, especially when we're dealing with lots of objects and methods.</p>
<h2 id="heading-constructor-functions-prototypes-a-powerful-combo">Constructor Functions + Prototypes: A Powerful Combo</h2>
<p>We've now seen how constructor functions act as blueprints for creating objects, and how using the prototype of a constructor function lets us efficiently share methods among all objects created from that blueprint.</p>
<p>This is a key pattern in JavaScript for creating reusable object structures.</p>
<h3 id="heading-okay-weve-covered-object-creation-and-efficient-methods-but-what-about-inheritance-with-constructor-functions">Okay, we've covered object creation and efficient methods... But what about inheritance with constructor functions?</h3>
<p>What if we want to create a <code>DeveloperPerson</code> blueprint that inherits from our <code>PersonConstructor</code> blueprint? So that <code>DeveloperPerson</code> objects automatically has <code>name</code>, <code>age</code>, and <code>greet</code>, but can also have its own special developer-related properties and methods?</p>
<p>That's where things get a bit more involved with constructor functions, and we'll need to use a special trick called <code>call()</code> to make inheritance work. Let's dive into that next.</p>
<h2 id="heading-inheritance-with-constructor-functions-passing-down-the-family-traits-the-constructor-way">Inheritance with Constructor Functions: Passing Down the Family Traits (the Constructor Way)</h2>
<p>Alright, we're making good progress. We've got constructor functions to create object blueprints, and prototypes to share methods efficiently. But one of the big reasons people use OOP is for inheritance – the idea of creating specialized objects that build upon more general ones.</p>
<p>Think back to our <code>Person</code> and <code>Developer</code> example. A <code>Developer</code> is a <code>Person</code>, right? They have a name, an age, maybe they greet people, but they also have developer-specific properties, like a favorite programming language and the ability to code.</p>
<p>How can we create a <code>DeveloperPersonConstructor</code> blueprint that inherits all the basic <code>PersonConstructor</code> stuff, and then adds its own developer-specific features? With constructor functions, you can use something called <code>call()</code>.</p>
<h3 id="heading-call-the-secret-inheritance-handshake"><code>call()</code>: The Secret Inheritance Handshake</h3>
<p><code>call()</code> is a function method that lets you do something a bit unusual: you can borrow a function from one object and run it in the context of another object. Sounds confusing? Let's simplify.</p>
<p>To illustrate <code>call()</code>, let's consider our <code>PersonConstructor</code>. We want to create a <code>DeveloperPersonConstructor</code> that also sets up <code>name</code> and <code>age</code> in the same way <code>PersonConstructor</code> does, before adding developer-specific properties.</p>
<p>This is where <code>call()</code> comes in. We can use <code>call()</code> to essentially say: "Hey <code>PersonConstructor</code>, run your code, but run it as if you were inside <code>DeveloperPersonConstructor</code>, and set up <code>name</code> and <code>age</code> for this <code>DeveloperPerson</code> object we're currently creating."</p>
<p>Let's see this in code to make it clearer:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PersonConstructor</span>(<span class="hljs-params">name, age</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name;
  <span class="hljs-built_in">this</span>.age = age;
}

PersonConstructor.prototype.greet = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, I'm <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>);
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DeveloperPersonConstructor</span>(<span class="hljs-params">name, age, programmingLanguage</span>) </span>{
  <span class="hljs-comment">//  --- "Borrow" the PersonConstructor to set up name and age! ---</span>
  PersonConstructor.call(<span class="hljs-built_in">this</span>, name, age); <span class="hljs-comment">//  &lt;--  The magic of 'call()'</span>

  <span class="hljs-comment">// --- Now, add developer-specific properties ---</span>
  <span class="hljs-built_in">this</span>.programmingLanguage = programmingLanguage;
  <span class="hljs-built_in">this</span>.code = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> is coding in <span class="hljs-subst">${<span class="hljs-built_in">this</span>.programmingLanguage}</span>`</span>);
  };
}
</code></pre>
<p>See that line: <a target="_blank" href="http://PersonConstructor.call"><code>PersonConstructor.call</code></a><code>(this, name, age);</code> ? That's the key to inheritance here. Let's break it down:</p>
<ul>
<li><p><a target="_blank" href="http://PersonConstructor.call"><code>PersonConstructor.call</code></a><code>(...)</code>: We're calling the <code>PersonConstructor</code> function, but not in the usual way. We're using <code>.call()</code>.</p>
</li>
<li><p><code>this</code>: The first argument to <code>call()</code> is crucial. It specifies what <code>this</code> should be inside the <code>PersonConstructor</code> function when it runs. Here, we're passing <code>this</code> from <code>DeveloperPersonConstructor</code>. Why? Because we want <code>PersonConstructor</code> to set up <code>name</code> and <code>age</code> on the <code>DeveloperPerson</code> object that's currently being created.</p>
</li>
<li><p><code>name, age</code>: These are the arguments we're passing to the <code>PersonConstructor</code> function itself. So, when <code>PersonConstructor</code> runs (thanks to <code>.call()</code>), it will receive <code>name</code> and <code>age</code> and do what it normally does: set <code>this.name = name</code> and <code>this.age = age</code>. But because <code>this</code> is actually the <code>DeveloperPerson</code> object, it sets these properties on the <code>DeveloperPerson</code> object.</p>
</li>
</ul>
<h3 id="heading-putting-it-all-together-creating-a-developerperson">Putting it all Together: Creating a <code>DeveloperPerson</code></h3>
<p>Now, let's create a <code>DeveloperPerson</code> object and see what happens:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> devPerson1 = <span class="hljs-keyword">new</span> DeveloperPersonConstructor(<span class="hljs-string">"Eve"</span>, <span class="hljs-number">30</span>, <span class="hljs-string">"JavaScript"</span>);

<span class="hljs-built_in">console</span>.log(devPerson1.name); <span class="hljs-comment">// Output: Eve (Inherited from PersonConstructor!)</span>
<span class="hljs-built_in">console</span>.log(devPerson1.age); <span class="hljs-comment">// Output: 30 (Inherited from PersonConstructor!)</span>
devPerson1.greet(); <span class="hljs-comment">// Output: (Oops! Error!)</span>
<span class="hljs-built_in">console</span>.log(devPerson1.programmingLanguage); <span class="hljs-comment">// Output: JavaScript (Developer-specific)</span>
devPerson1.code(); <span class="hljs-comment">// Output: Eve is coding in JavaScript (Developer-specific)</span>
</code></pre>
<p>Notice that <code>devPerson1.name</code> and <code>devPerson1.age</code> are there. <code>DeveloperPersonConstructor</code> borrowed the part of <code>PersonConstructor</code> that sets up those basic properties. And we also have <code>devPerson1.programmingLanguage</code> and <code>devPerson1.code()</code> which are specific to developers.</p>
<h3 id="heading-uh-oh-wheres-greet">Uh Oh! Where's <code>greet()</code>?</h3>
<p>But wait, <code>devPerson1.greet()</code> is throwing an error. Why? Because even though we borrowed the constructor logic from <code>PersonConstructor</code>, we haven't yet set up the prototype chain for inheritance of prototype methods like <code>greet()</code>.</p>
<p>Right now, <code>devPerson1</code>'s prototype is just the default object prototype (<code>Object.prototype</code>). It's not inheriting from <code>PersonConstructor.prototype</code>. We need to fix that.</p>
<h3 id="heading-setting-the-prototype-chain-for-constructor-inheritance">Setting the Prototype Chain for Constructor Inheritance</h3>
<p>To make <code>DeveloperPersonConstructor</code> objects also inherit prototype methods from <code>PersonConstructor</code>, we need to manually adjust the prototype chain. We can do this using <code>Object.create()</code> again.</p>
<p>We want the prototype of <code>DeveloperPersonConstructor</code> to be an object that inherits from <code>PersonConstructor.prototype</code>.</p>
<p>Here's the code:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PersonConstructor</span>(<span class="hljs-params">name, age</span>) </span>{
  <span class="hljs-built_in">this</span>.name = name;
  <span class="hljs-built_in">this</span>.age = age;
}

PersonConstructor.prototype.greet = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, I'm <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>);
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">DeveloperPersonConstructor</span>(<span class="hljs-params">name, age, programmingLanguage</span>) </span>{
  PersonConstructor.call(<span class="hljs-built_in">this</span>, name, age);
  <span class="hljs-built_in">this</span>.programmingLanguage = programmingLanguage;
  <span class="hljs-built_in">this</span>.code = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> is coding in <span class="hljs-subst">${<span class="hljs-built_in">this</span>.programmingLanguage}</span>`</span>);
  };
}

<span class="hljs-comment">// ---  Set up the Prototype Chain for Inheritance! ---</span>
DeveloperPersonConstructor.prototype = <span class="hljs-built_in">Object</span>.create(
  PersonConstructor.prototype
);
</code></pre>
<p>That line <code>DeveloperPersonConstructor.prototype = Object.create(PersonConstructor.prototype);</code> is doing the magic. It's saying, "Hey JavaScript, set the prototype of <code>DeveloperPersonConstructor</code> to be a new object that inherits from <code>PersonConstructor.prototype</code>."</p>
<p>Now, let's try <code>devPerson1.greet()</code> again:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> devPerson1 = <span class="hljs-keyword">new</span> DeveloperPersonConstructor(<span class="hljs-string">"Eve"</span>, <span class="hljs-number">30</span>, <span class="hljs-string">"JavaScript"</span>);

devPerson1.greet(); <span class="hljs-comment">// Output: Hello, I'm Eve  - 🎉 It works now!</span>
</code></pre>
<p><code>devPerson1.greet()</code> now works. <code>devPerson1</code> is inheriting the <code>greet()</code> method from <code>PersonConstructor.prototype</code> through the prototype chain we just set up.</p>
<h3 id="heading-lets-trace-the-prototype-chain">Let's Trace the Prototype Chain</h3>
<p>Let's really understand what's happening when we do <code>devPerson1.greet()</code>:</p>
<ol>
<li><p>JavaScript checks: Does <code>devPerson1</code> itself have a <code>greet</code> property? No.</p>
</li>
<li><p>JavaScript looks at <code>devPerson1</code>'s prototype: <code>DeveloperPersonConstructor.prototype</code>. Does it have a <code>greet</code>property? No, we only added developer-specific methods or properties to <code>DeveloperPersonConstructor</code> directly, not to its prototype in our example. (We could add developer-specific prototype methods later).</p>
</li>
<li><p>JavaScript goes up the prototype chain to <code>DeveloperPersonConstructor.prototype</code>'s prototype: <code>PersonConstructor.prototype</code>. Does it have a <code>greet</code> property? Yes. We defined <code>PersonConstructor.prototype.greet = function() { ... };</code></p>
</li>
<li><p>JavaScript finds <code>greet()</code> on <code>PersonConstructor.prototype</code>, and executes it in the context of <code>devPerson1</code> (so <code>this.name</code> inside <code>greet()</code> refers to <code>devPerson1.name</code>).</p>
</li>
</ol>
<p>Prototype chain in action. <code>devPerson1</code> -&gt; <code>DeveloperPersonConstructor.prototype</code> -&gt; <code>PersonConstructor.prototype</code>-&gt; <code>Object.prototype</code>.</p>
<h3 id="heading-going-even-further-javascript-developer-person">Going Even Further: JavaScript Developer Person</h3>
<p>We can even create longer inheritance chains. Let's say we want to create a <code>JavaScriptDeveloperPersonConstructor</code> that's a special type of <code>DeveloperPersonConstructor</code>, maybe with a specific JavaScript framework preference.</p>
<p>We can do the same pattern:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">JavaScriptDeveloperPersonConstructor</span>(<span class="hljs-params">name, age, framework</span>) </span>{
  <span class="hljs-comment">//  "Borrow" from DeveloperPersonConstructor first!</span>
  DeveloperPersonConstructor.call(<span class="hljs-built_in">this</span>, name, age, <span class="hljs-string">"JavaScript"</span>); <span class="hljs-comment">// Hardcoded "JavaScript"</span>
  <span class="hljs-built_in">this</span>.framework = framework;
  <span class="hljs-built_in">this</span>.codeJavaScript = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// Specific to JavaScript developers</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> is coding in JavaScript with <span class="hljs-subst">${<span class="hljs-built_in">this</span>.framework}</span>`</span>);
  };
}

<span class="hljs-comment">// Set up prototype chain: JavaScriptDeveloperPerson -&gt; DeveloperPerson -&gt; Person</span>
JavaScriptDeveloperPersonConstructor.prototype = <span class="hljs-built_in">Object</span>.create(
  DeveloperPersonConstructor.prototype
);
</code></pre>
<p>Now we have a three-level inheritance chain.</p>
<h3 id="heading-constructor-functions-powerful-but-a-bit-verbose">Constructor Functions: Powerful, but a Bit... Verbose?</h3>
<p>Constructor functions and prototypes are really powerful. They are the fundamental way JavaScript achieves OOP-like behavior. However, as you can see, setting up inheritance with <code>call()</code> and <code>Object.create()</code> can get a bit wordy and tricky to read, especially as inheritance chains get longer.</p>
<p>And guess what? The JavaScript folks noticed this too. In 2015, a new, cleaner syntax for creating object blueprints was introduced in JavaScript.</p>
<h2 id="heading-enter-es6-classes-syntactic-sugar-for-prototypes">Enter ES6 Classes: Syntactic Sugar for Prototypes</h2>
<p>You see, in 2015, JavaScript developers recognized that using prototypes and constructor functions directly to achieve class-like patterns could become verbose and less straightforward to manage as applications grew. Therefore, they introduced the <code>class</code> syntax in ECMAScript 2015 (ES6).</p>
<p>Classes in JavaScript provide a much cleaner and more familiar way to create object blueprints and set up inheritance. But here’s the super important thing to remember: JavaScript classes are still built on top of prototypes. They don't fundamentally change how JavaScript OOP works. They are just syntactic sugar – a nicer, easier way to write code that's still using prototypes behind the scenes.</p>
<p>In the next section, we'll see how to rewrite our <code>Person</code>, <code>DeveloperPerson</code>, and <code>JavaScriptDeveloperPerson</code> examples using the new <code>class</code> syntax, and you'll see how much cleaner and more class-like (pun intended) it feels, while using the power of JavaScript prototypes.</p>
<h2 id="heading-es6-classes-class-syntax-prototypes-in-disguise">ES6 Classes: Class Syntax – Prototypes in Disguise</h2>
<p>Okay, we've wrestled with constructor functions and <code>call()</code> and <code>Object.create()</code> to get inheritance working with prototypes. It's powerful, but let's be honest, it can feel a little verbose and indirect, especially if you're used to class-based languages.</p>
<p>That's where ES6 classes come to the rescue. They offer a much more streamlined and class-like syntax for creating object blueprints in JavaScript.</p>
<p>Let's rewrite our <code>PersonConstructor</code> example using the <code>class</code> syntax. Get ready for a breath of fresh air.</p>
<h3 id="heading-personclass-constructor-function-reimagined-as-a-class"><code>PersonClass</code> - Constructor Function Reimagined as a Class</h3>
<p>Here's how we can define our <code>Person</code> blueprint as a class:</p>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PersonClass</span> </span>{
  <span class="hljs-comment">//  Using the 'class' keyword!</span>
  <span class="hljs-keyword">constructor</span>(name, age) {
    <span class="hljs-comment">//  'constructor' method - like our old constructor function</span>
    <span class="hljs-built_in">this</span>.name = name; <span class="hljs-comment">//  Still using 'this' in the constructor</span>
    <span class="hljs-built_in">this</span>.age = age;
  }

  greet() {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Hello, I'm <span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span>`</span>);
  }
}
</code></pre>
<p>Doesn't that look much cleaner and more organized? Let's break down the class syntax:</p>
<ul>
<li><p><code>class PersonClass { ... }</code>: We start with the <code>class</code> keyword, followed by the class name (<code>PersonClass</code> in this case). Class names are conventionally capitalized.</p>
</li>
<li><p><code>constructor(name, age) { ... }</code>: Inside the class, we have a special method called <code>constructor</code>. This is like our old <code>PersonConstructor</code> function. It's where we put the code to initialize the properties of a new <code>PersonClass</code> object when it's created with <code>new</code>. We still use <code>this</code> inside the <code>constructor</code> to refer to the new object being created.</p>
</li>
<li><p><code>greet() { ... }</code>: This is how we define methods in a class. We simply write the method name (<code>greet</code>), followed by parentheses for parameters (none in this case), and then the method body in curly braces. Notice that we don't use the <code>function</code> keyword here. It's just <code>greet() { ... }</code>.</p>
</li>
</ul>
<h3 id="heading-creating-objects-from-a-class-still-using-new">Creating Objects from a Class - Still Using <code>new</code></h3>
<p>To create objects from our <code>PersonClass</code> blueprint, we still use the <code>new</code> keyword, just like we did with constructor functions:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> classPerson1 = <span class="hljs-keyword">new</span> PersonClass(<span class="hljs-string">"Charlie"</span>, <span class="hljs-number">28</span>);
<span class="hljs-keyword">const</span> classPerson2 = <span class="hljs-keyword">new</span> PersonClass(<span class="hljs-string">"Diana"</span>, <span class="hljs-number">32</span>);

<span class="hljs-built_in">console</span>.log(classPerson1.name); <span class="hljs-comment">// Output: Charlie</span>
classPerson1.greet(); <span class="hljs-comment">// Output: Hello, I'm Charlie</span>
</code></pre>
<p>Yep, it works exactly the same way as our constructor function example, but the class syntax is just much more readable and less cluttered.</p>
<h3 id="heading-developerpersonclass-inheritance-made-easy-with-extends"><code>DeveloperPersonClass</code> - Inheritance Made Easy with <code>extends</code></h3>
<p>Now, let's tackle inheritance using classes. Remember how we had to use <code>call()</code> and <code>Object.create()</code> to get <code>DeveloperPersonConstructor</code> to inherit from <code>PersonConstructor</code>? With classes, inheritance becomes super straightforward using the <code>extends</code> keyword.</p>
<p>Here's how we can rewrite <code>DeveloperPersonConstructor</code> as a <code>DeveloperPersonClass</code> that inherits from <code>PersonClass</code>:</p>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DeveloperPersonClass</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">PersonClass</span> </span>{
  <span class="hljs-comment">//  'extends' for inheritance!</span>
  <span class="hljs-keyword">constructor</span>(name, age, programmingLanguage) {
    <span class="hljs-built_in">super</span>(name, age); <span class="hljs-comment">//  'super()' calls the parent class constructor!</span>
    <span class="hljs-built_in">this</span>.programmingLanguage = programmingLanguage;
  }

  code() {
    <span class="hljs-comment">// Developer-specific method</span>
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`<span class="hljs-subst">${<span class="hljs-built_in">this</span>.name}</span> is coding in <span class="hljs-subst">${<span class="hljs-built_in">this</span>.programmingLanguage}</span>`</span>);
  }
}
</code></pre>
<p>Look at that. Inheritance in classes is declared using the <code>extends</code> keyword: <code>class DeveloperPersonClass extends PersonClass {...}</code>. This line alone says, "Hey JavaScript, <code>DeveloperPersonClass</code> should inherit from <code>PersonClass</code>."</p>
<p>Inside the <code>DeveloperPersonClass</code> constructor, we have this line: <code>super(name, age);</code>. <code>super()</code> is crucial for class inheritance. It's how we call the constructor of the parent class (<code>PersonClass</code> in this case). When we call <code>super(name, age)</code>, it's essentially doing the same thing as <code>PersonConstructor.call(this, name, age)</code> in our constructor function example—it's running the <code>PersonClass</code> constructor to set up the inherited properties (<code>name</code> and <code>age</code>) on the <code>DeveloperPersonClass</code> object.</p>
<p>After calling <code>super()</code>, we can then add any developer-specific properties or methods to our <code>DeveloperPersonClass</code>, like <code>this.programmingLanguage = programmingLanguage;</code> and the <code>code()</code> method.</p>
<h3 id="heading-using-developerpersonclass-inheritance-in-action-cleaner-syntax">Using <code>DeveloperPersonClass</code> - Inheritance in Action, Cleaner Syntax</h3>
<p>Let's create a <code>DeveloperPersonClass</code> object and see inheritance in action with this cleaner syntax:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> classDevPerson1 = <span class="hljs-keyword">new</span> DeveloperPersonClass(<span class="hljs-string">"Eve"</span>, <span class="hljs-number">35</span>, <span class="hljs-string">"JavaScript"</span>);

<span class="hljs-built_in">console</span>.log(classDevPerson1.name); <span class="hljs-comment">// Output: Eve (Inherited from PersonClass!)</span>
<span class="hljs-built_in">console</span>.log(classDevPerson1.age); <span class="hljs-comment">// Output: 35 (Inherited from PersonClass!)</span>
classDevPerson1.greet(); <span class="hljs-comment">// Output: Hello, I'm Eve (Inherited from PersonClass!)</span>
<span class="hljs-built_in">console</span>.log(classDevPerson1.programmingLanguage); <span class="hljs-comment">// Output: JavaScript (Developer-specific)</span>
classDevPerson1.code(); <span class="hljs-comment">// Output: Eve is coding in JavaScript (Developer-specific)</span>
</code></pre>
<p>It works exactly as expected. <code>classDevPerson1</code> inherits <code>name</code>, <code>age</code>, and <code>greet()</code> from <code>PersonClass</code> and also has its own <code>programmingLanguage</code> and <code>code()</code> methods. But the class syntax makes the inheritance relationship much more obvious and easier to work with.</p>
<h3 id="heading-classes-syntactic-sugar-prototype-power-underneath">Classes: Syntactic Sugar, Prototype Power Underneath</h3>
<p>Let's be crystal clear again: JavaScript classes are syntactic sugar over prototypes. They are a more user-friendly way to write code that is still based on prototypes and constructor functions behind the scenes.</p>
<p>When you define a class, JavaScript is actually doing these things for you under the hood:</p>
<ul>
<li><p>It's creating a constructor function (like our <code>PersonConstructor</code>).</p>
</li>
<li><p>It's setting up the <code>.prototype</code> property of that constructor function.</p>
</li>
<li><p>When you use <code>extends</code>, it's using <code>Object.create()</code> and <code>call() to</code> set up the prototype chain for inheritance.</p>
</li>
</ul>
<p>Classes don't change the fundamental prototype-based nature of JavaScript OOP. They just give us a more familiar and less verbose syntax to work with it.</p>
<h3 id="heading-so-are-classes-just-fake-classes">So, Are Classes Just "Fake" Classes?</h3>
<p>Some people argue that JavaScript classes are “fake” because they’re merely syntactic sugar. But honestly, that’s not the point at all. Syntactic sugar is awesome—it makes our code easier to read, write, and maintain. For those coming from a class-based language background, classes make object-oriented programming in JavaScript much more approachable and understandable.</p>
<p>The key takeaway is that while classes give you a neat, familiar syntax, you still need to understand the underlying mechanism: prototypes. Classes are just a friendly layer on top of JavaScript’s prototype system.</p>
<h2 id="heading-whats-next-more-class-features-and-real-world-examples">What’s Next? More Class Features and Real-World Examples</h2>
<p>Alright, now that you’re comfortable with the idea of classes, it’s time to see them in action. Understanding the theory is only half the battle—we need some practical examples.</p>
<p>And to solidify your understanding, let’s walk through building a classic example: a basic to-do list app. While a to-do app is still relatively simple in concept, it introduces enough front-end interaction to see how classes can organize front-end JavaScript code for interactive elements in a manageable way for learning.</p>
<p>Imagine you want to build a really basic to-do app. What do you need to manage?</p>
<ul>
<li><p>To-dos: Each to-do item has a description and a status (done or not).</p>
</li>
<li><p>Actions: You’ll want to add new to-dos, mark them as complete, delete them, and list them.</p>
</li>
</ul>
<p>This naturally leads us to think of a “ToDo” item as an object, and if you’re creating many to-do items, a <code>ToDo</code> class is a perfect blueprint.</p>
<h3 id="heading-setting-up-your-files">Setting Up Your Files</h3>
<p>Before writing any code, create two files in the same folder:</p>
<ul>
<li><p><code>index.html</code>: This is the webpage structure.</p>
</li>
<li><p><code>script.js</code>: This is where your JavaScript code with classes will live.</p>
</li>
</ul>
<p>You can use any text editor (like VS Code, Sublime Text, or even Notepad) to create these files.</p>
<h3 id="heading-creating-the-todo-class">Creating the ToDo Class</h3>
<p>Let’s start by building our <code>ToDo</code> class. Copy and paste the following code into your <code>script.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ToDo</span> </span>{

<span class="hljs-keyword">constructor</span>(description) {

<span class="hljs-built_in">this</span>.description = description; <span class="hljs-comment">// Every to-do needs a description</span>

<span class="hljs-built_in">this</span>.completed = <span class="hljs-literal">false</span>; <span class="hljs-comment">// By default, it's not completed</span>

}

markComplete() {

<span class="hljs-built_in">this</span>.completed = <span class="hljs-literal">true</span>;

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"${this.description}"</span> marked <span class="hljs-keyword">as</span> complete!);

}

<span class="hljs-comment">// More methods (e.g., for editing the to-do) can be added later.</span>

}
</code></pre>
<p>Notice how clean that is. The <code>constructor</code> sets up the description and completed status for each new to-do item. The <code>markComplete()</code> method updates the status and logs a confirmation message.</p>
<h3 id="heading-building-the-todolist-class">Building the ToDoList Class</h3>
<p>Next, we’ll build a <code>ToDoList</code> class to manage our collection of to-dos. Add the following code to your <code>script.js</code> file, below the <code>ToDo</code> class:</p>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ToDoList</span> </span>{

<span class="hljs-keyword">constructor</span>() {

<span class="hljs-built_in">this</span>.todos = []; <span class="hljs-comment">// Start with an empty array of to-dos</span>

}

addTodo(description) {

<span class="hljs-keyword">const</span> newTodo = <span class="hljs-keyword">new</span> ToDo(description); <span class="hljs-comment">// Create a new ToDo object</span>

<span class="hljs-built_in">this</span>.todos.push(newTodo); <span class="hljs-comment">// Add it to our list</span>

<span class="hljs-built_in">this</span>.renderTodoList(); <span class="hljs-comment">// Update the webpage display</span>

}

listTodos() {

<span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.todos; <span class="hljs-comment">// Return the array of todos (for further processing or rendering)</span>

}

markTodoComplete(index) {

<span class="hljs-keyword">if</span> (index &gt;= <span class="hljs-number">0</span> &amp;&amp; index &lt; <span class="hljs-built_in">this</span>.todos.length) {

<span class="hljs-built_in">this</span>.todos[index].markComplete();

<span class="hljs-built_in">this</span>.renderTodoList(); <span class="hljs-comment">// Update the display after marking complete</span>

}

}

renderTodoList() {

<span class="hljs-keyword">const</span> todoListElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'todoList'</span>);

todoListElement.innerHTML = <span class="hljs-string">''</span>; <span class="hljs-comment">// Clear the current list in HTML</span>

<span class="hljs-built_in">this</span>.todos.forEach(<span class="hljs-function">(<span class="hljs-params">todo, index</span>) =&gt;</span> {

<span class="hljs-keyword">const</span> listItem = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'li'</span>);

listItem.textContent = todo.description;

<span class="hljs-keyword">if</span> (todo.completed) {

listItem.classList.add(<span class="hljs-string">'completed'</span>); <span class="hljs-comment">// Add CSS class for styling completed items</span>

}

<span class="hljs-comment">// Create a "Complete" button for each to-do</span>

<span class="hljs-keyword">const</span> completeButton = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'button'</span>);

completeButton.textContent = <span class="hljs-string">'Complete'</span>;

completeButton.onclick = <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">this</span>.markTodoComplete(index);

listItem.appendChild(completeButton);

todoListElement.appendChild(listItem);

});

}

}
</code></pre>
<p>In this class:</p>
<ul>
<li><p>The <code>constructor</code> initializes an empty array to hold our to-do items.</p>
</li>
<li><p><code>addTodo(description)</code> creates a new <code>ToDo</code> object and adds it to the array, then calls <code>renderTodoList()</code> to update the display.</p>
</li>
<li><p><code>listTodos()</code> returns the list of to-dos.</p>
</li>
<li><p><code>markTodoComplete(index)</code> marks a specific to-do as complete and refreshes the display.</p>
</li>
<li><p><code>renderTodoList()</code> finds the HTML element with the ID <code>todoList</code>, clears its content, and then creates list items for each to-do, including a “Complete” button.</p>
</li>
</ul>
<h3 id="heading-creating-the-html-structure">Creating the HTML Structure</h3>
<p>Next, open your <code>index.html</code> file and paste in the following HTML code:</p>
<pre><code class="lang-javascript">&lt;!DOCTYPE html&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My Simple To-Do App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">

    <span class="hljs-comment">/* Simple CSS to style completed items */</span>

    <span class="hljs-selector-class">.completed</span> {

      <span class="hljs-attribute">text-decoration</span>: line-through;

      <span class="hljs-attribute">color</span>: gray;

    }

  </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My To-Do List<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"todoInput"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter new to-do..."</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"addButton"</span>&gt;</span>Add To-Do<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"todoList"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"script.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></span>
</code></pre>
<p>This HTML file sets up:</p>
<ul>
<li><p>A heading for your to-do list.</p>
</li>
<li><p>An input box (with <code>id="todoInput"</code>) for entering new to-dos.</p>
</li>
<li><p>An “Add To-Do” button (with <code>id="addButton"</code>).</p>
</li>
<li><p>An empty unordered list (with <code>id="todoList"</code>) where your to-dos will appear.</p>
</li>
<li><p>A link to the <code>script.js</code> file that contains your JavaScript code.</p>
</li>
</ul>
<h3 id="heading-making-it-all-work-together">Making It All Work Together</h3>
<p>Finally, let’s hook up our HTML elements with our JavaScript. At the bottom of your <code>script.js</code> file, add this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> myTodoList = <span class="hljs-keyword">new</span> ToDoList(); <span class="hljs-comment">// Create an instance of ToDoList</span>

<span class="hljs-comment">// Get references to the HTML elements</span>

<span class="hljs-keyword">const</span> addButton = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"addButton"</span>);

<span class="hljs-keyword">const</span> todoInput = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"todoInput"</span>);

<span class="hljs-comment">// Listen for clicks on the "Add To-Do" button</span>

addButton.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> todoText = todoInput.value.trim(); <span class="hljs-comment">// Get the text from the input box</span>

  <span class="hljs-keyword">if</span> (todoText) {
    <span class="hljs-comment">// Only add if the input is not empty</span>

    myTodoList.addTodo(todoText); <span class="hljs-comment">// Add the new to-do</span>

    todoInput.value = <span class="hljs-string">""</span>; <span class="hljs-comment">// Clear the input box</span>
  }
});

<span class="hljs-comment">// Render the to-do list initially (it will be empty to start)</span>

myTodoList.renderTodoList();
</code></pre>
<p>This code does the following:</p>
<ul>
<li><p>Creates an instance of the <code>ToDoList</code> class.</p>
</li>
<li><p>Finds the HTML elements for the input and button.</p>
</li>
<li><p>This code adds an event listener to the HTML button element that has the ID "addButton". This listener is set to react to "click" events on this button. When the "Add To-Do" button is clicked, the code inside the event listener function will execute. This code takes the text that the user has typed into the HTML input field with the ID "todoInput" and adds it as a new to-do item to our list.</p>
</li>
<li><p>Initially renders the to-do list on the webpage.</p>
</li>
</ul>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/vEYBdQe" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h3 id="heading-your-challenge-go-proto-style">Your Challenge: Go Proto-Style</h3>
<p>Now that you’ve seen how classes can make building this to-do app more structured, here’s a challenge: Try building the same to-do app without using the <code>class</code> keyword. Use object literals and prototypes instead. Think about:</p>
<ul>
<li><p>How would you create a <code>ToDo</code> “blueprint” using a constructor function and prototypes?</p>
</li>
<li><p>How would you add the <code>markComplete()</code> method to the <code>ToDo</code> prototype?</p>
</li>
<li><p>How would you structure a <code>ToDoList</code> “blueprint” similarly?</p>
</li>
</ul>
<p>By building the same app using both approaches, you’ll really understand that classes are just a nicer, more familiar way of writing prototype-based code.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations! You’ve built a basic, interactive to-do app using JavaScript classes and HTML. You now see how classes help you organize code and encapsulate related functionality. While classes are just syntactic sugar over prototypes, they make it much easier to write, read, and maintain your code—especially as your applications grow.</p>
<p>Your next step? Experiment with the prototype approach and compare it with the class-based approach. The more you code, the more natural these concepts will become. Happy coding, and keep building cool stuff.</p>
<p>If you have any questions, feel free to find me on Twitter at <a target="_blank" href="https://x.com/sprucekhalifa">@sprucekhalifa</a>, and don’t forget to follow me for more tips and updates. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Simple Portfolio Website With HTML and CSS ]]>
                </title>
                <description>
                    <![CDATA[ While browsing through some of my old projects, I stumbled upon a portfolio I worked on a while back. The funny thing? I never used it. So, I decided to give it a fresh look and thought, why not share it with you? As a developer, having a portfolio i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-simple-portfolio-website-with-html-and-css/</link>
                <guid isPermaLink="false">67859c6915988a75c229dee2</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Beginner Developers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ portfolio ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Mon, 13 Jan 2025 23:06:17 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1736809428369/d28ee1e5-c11b-48fa-9ccd-b7fbaedd52da.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>While browsing through some of my old projects, I stumbled upon a portfolio I worked on a while back. The funny thing? I never used it. So, I decided to give it a fresh look and thought, why not share it with you?</p>
<p>As a developer, having a portfolio is important. It’s your personal space to showcase your skills, share projects, and impress potential employers. Whether you’re aiming to build an online presence, share your work with friends, or take your career to the next level, a portfolio is the perfect way to highlight what you can do.</p>
<p>In this article, I’ll guide you through building a simple portfolio website using just HTML and CSS. By the end, you’ll have a fully functional portfolio site ready to share with anyone.</p>
<h3 id="heading-what-the-finished-portfolio-looks-like">What the Finished Portfolio Looks Like:</h3>
<p>Before we get started, here’s a preview of what your portfolio will look like once we’re done:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1736721383725/d8c88f72-5e79-466d-9fe0-d8814be7f1cb.png" alt="d8c88f72-5e79-466d-9fe0-d8814be7f1cb" class="image--center mx-auto" width="2412" height="4696" loading="lazy"></p>
<p>If you’d prefer to skip ahead, you can get the full code on <a target="_blank" href="https://github.com/iamspruce/Simple-HTML-CSS-Portfolio">GitHub</a>.</p>
<h2 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-project-overview-and-setup">Project Overview and Setup</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-header-and-hero-section">How to Build the Header and Hero Section</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-about-section">How to Build the About Section</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-work-section">How to Build the Work Section</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-contact-section-and-footer">How to Build the Contact Section and Footer</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<h2 id="heading-project-overview-and-setup">Project Overview and Setup</h2>
<p>Before we start coding, let’s take a look at the basic structure of the project. Here's how everything will be organized:</p>
<pre><code class="lang-bash">/assets
  - background_image.jpg
  - user.png
  - icon-github.svg
  - icon-twitter.svg
  - logo1.png
  - logo2.png
  - logo3.png
index.html
styles.css
</code></pre>
<p>This folder structure keeps things neat and organized. The <code>/assets</code> folder will hold all of your images and icons that will be used throughout the website, while the <code>index.html</code> file will contain the structure of your portfolio, and <code>styles.css</code> will control how everything looks.</p>
<h3 id="heading-setting-up-the-html-file">Setting Up the HTML File</h3>
<p>Let's start with the basic HTML structure. Open your <code>index.html</code> file and add the following code:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"styles.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Spruce - Dev Portfolio<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Content will go here --&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Here’s a breakdown of what this code does:</p>
<ol>
<li><p><strong>DOCTYPE</strong>: This tells the browser that this is an HTML5 document.</p>
</li>
<li><p><strong>meta charset</strong>: Defines the character encoding, which helps display text properly.</p>
</li>
<li><p><strong>meta viewport</strong>: Ensures the website is responsive on different screen sizes.</p>
</li>
<li><p><strong>link to styles.css</strong>: Links the <code>styles.css</code> file for styling your website.</p>
</li>
<li><p><strong>title</strong>: This is the text that appears in the browser tab when you open the website.</p>
</li>
</ol>
<p>Now that our HTML file is set up, we’ll move on to the CSS.</p>
<h3 id="heading-setting-up-the-css-file">Setting Up the CSS File</h3>
<p>Let’s now add some basic styling using a CSS reset. This helps eliminate browser inconsistencies by normalizing styles across different browsers.</p>
<p>Here’s the basic CSS reset you’ll need:</p>
<pre><code class="lang-css"><span class="hljs-comment">/**
 * CORE CONFIG
 * This powers everything from utility class generation to breakpoints
 * to enabling/disabling pre-built components/utilities.
 */</span>
<span class="hljs-comment">/* Box sizing rules */</span>
*,
*<span class="hljs-selector-pseudo">::before</span>,
*<span class="hljs-selector-pseudo">::after</span> {
  <span class="hljs-attribute">box-sizing</span>: border-box;
  <span class="hljs-attribute">font-family</span>: sans-serif;
}

<span class="hljs-comment">/* Remove default margin */</span>
<span class="hljs-selector-tag">body</span>,
<span class="hljs-selector-tag">h1</span>,
<span class="hljs-selector-tag">h2</span>,
<span class="hljs-selector-tag">h3</span>,
<span class="hljs-selector-tag">h4</span>,
<span class="hljs-selector-tag">p</span>,
<span class="hljs-selector-tag">figure</span>,
<span class="hljs-selector-tag">blockquote</span>,
<span class="hljs-selector-tag">dl</span>,
<span class="hljs-selector-tag">dd</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-comment">/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */</span>
<span class="hljs-selector-tag">ul</span><span class="hljs-selector-attr">[role=<span class="hljs-string">"list"</span>]</span>,
<span class="hljs-selector-tag">ol</span><span class="hljs-selector-attr">[role=<span class="hljs-string">"list"</span>]</span> {
  <span class="hljs-attribute">list-style</span>: none;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-comment">/* Set core root defaults */</span>
<span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:focus-within</span> {
  <span class="hljs-attribute">scroll-behavior</span>: smooth;
}

<span class="hljs-comment">/* Set core body defaults */</span>
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">text-rendering</span>: optimizeSpeed;
  <span class="hljs-attribute">letter-spacing</span>: -<span class="hljs-number">0.01em</span>;
}

<span class="hljs-comment">/* All elements that don't have a class get default styles */</span>
<span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:not(</span><span class="hljs-selector-attr">[class]</span>) {
  <span class="hljs-attribute">text-decoration-skip-ink</span>: auto;
}

<span class="hljs-comment">/* Make images easier to work with */</span>
<span class="hljs-selector-tag">img</span>,
<span class="hljs-selector-tag">picture</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">display</span>: block;
}

<span class="hljs-comment">/* Inherit fonts for inputs and buttons */</span>
<span class="hljs-selector-tag">input</span>,
<span class="hljs-selector-tag">button</span>,
<span class="hljs-selector-tag">textarea</span>,
<span class="hljs-selector-tag">select</span> {
  <span class="hljs-attribute">font</span>: inherit;
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-reduced-motion:</span> reduce) {
  <span class="hljs-selector-tag">html</span><span class="hljs-selector-pseudo">:focus-within</span> {
    <span class="hljs-attribute">scroll-behavior</span>: auto;
  }
}

<span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">outline</span>: <span class="hljs-number">2px</span> dashed <span class="hljs-number">#00ff19</span>;
  <span class="hljs-attribute">outline-offset</span>: <span class="hljs-number">0.25rem</span>;
}

<span class="hljs-selector-tag">main</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">outline</span>: none;
}
</code></pre>
<p>This reset clears any default margins and paddings, ensuring that your layout remains consistent across browsers. You can find more info about what the code does in the comments.</p>
<h3 id="heading-sizing-and-spacing-with-utopia">Sizing and Spacing with Utopia</h3>
<p>For spacing and typography, we’ll use a flexible system from Utopia, a tool designed to make responsive typography easier to implement. Here’s the CSS that will give us scalable, adjustable spacing and font sizes:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* @link https://utopia.fyi/type/calculator?c=320,18,1.2,1240,20,1.25,5,2,&amp;s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&amp;g=s,l,xl,12 */</span>

<span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--step--2</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">0.7813rem</span>, <span class="hljs-number">0.7747rem</span> + <span class="hljs-number">0.0326vw</span>, <span class="hljs-number">0.8rem</span>);
  <span class="hljs-attribute">--step--1</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">0.9375rem</span>, <span class="hljs-number">0.9158rem</span> + <span class="hljs-number">0.1087vw</span>, <span class="hljs-number">1rem</span>);
  <span class="hljs-attribute">--step-0</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.125rem</span>, <span class="hljs-number">1.0815rem</span> + <span class="hljs-number">0.2174vw</span>, <span class="hljs-number">1.25rem</span>);
  <span class="hljs-attribute">--step-1</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.35rem</span>, <span class="hljs-number">1.2761rem</span> + <span class="hljs-number">0.3696vw</span>, <span class="hljs-number">1.5625rem</span>);
  <span class="hljs-attribute">--step-2</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.62rem</span>, <span class="hljs-number">1.5041rem</span> + <span class="hljs-number">0.5793vw</span>, <span class="hljs-number">1.9531rem</span>);
  <span class="hljs-attribute">--step-3</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.944rem</span>, <span class="hljs-number">1.771rem</span> + <span class="hljs-number">0.8651vw</span>, <span class="hljs-number">2.4414rem</span>);
  <span class="hljs-attribute">--step-4</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">2.3328rem</span>, <span class="hljs-number">2.0827rem</span> + <span class="hljs-number">1.2504vw</span>, <span class="hljs-number">3.0518rem</span>);
  <span class="hljs-attribute">--step-5</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">2.7994rem</span>, <span class="hljs-number">2.4462rem</span> + <span class="hljs-number">1.7658vw</span>, <span class="hljs-number">3.8147rem</span>);
}

<span class="hljs-comment">/* @link https://utopia.fyi/space/calculator?c=320,18,1.2,1240,20,1.25,5,2,&amp;s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&amp;g=s,l,xl,12 */</span>

<span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">--space-3xs</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">0.3125rem</span>, <span class="hljs-number">0.3125rem</span> + <span class="hljs-number">0vw</span>, <span class="hljs-number">0.3125rem</span>);
  <span class="hljs-attribute">--space-2xs</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">0.5625rem</span>, <span class="hljs-number">0.5408rem</span> + <span class="hljs-number">0.1087vw</span>, <span class="hljs-number">0.625rem</span>);
  <span class="hljs-attribute">--space-xs</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">0.875rem</span>, <span class="hljs-number">0.8533rem</span> + <span class="hljs-number">0.1087vw</span>, <span class="hljs-number">0.9375rem</span>);
  <span class="hljs-attribute">--space-s</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.125rem</span>, <span class="hljs-number">1.0815rem</span> + <span class="hljs-number">0.2174vw</span>, <span class="hljs-number">1.25rem</span>);
  <span class="hljs-attribute">--space-m</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.6875rem</span>, <span class="hljs-number">1.6223rem</span> + <span class="hljs-number">0.3261vw</span>, <span class="hljs-number">1.875rem</span>);
  <span class="hljs-attribute">--space-l</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">2.25rem</span>, <span class="hljs-number">2.163rem</span> + <span class="hljs-number">0.4348vw</span>, <span class="hljs-number">2.5rem</span>);
  <span class="hljs-attribute">--space-xl</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">3.375rem</span>, <span class="hljs-number">3.2446rem</span> + <span class="hljs-number">0.6522vw</span>, <span class="hljs-number">3.75rem</span>);
  <span class="hljs-attribute">--space-2xl</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">4.5rem</span>, <span class="hljs-number">4.3261rem</span> + <span class="hljs-number">0.8696vw</span>, <span class="hljs-number">5rem</span>);
  <span class="hljs-attribute">--space-3xl</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">6.75rem</span>, <span class="hljs-number">6.4891rem</span> + <span class="hljs-number">1.3043vw</span>, <span class="hljs-number">7.5rem</span>);
}
</code></pre>
<p>These CSS variables give you flexible, responsive font sizes and spacing, based on the viewport size. For instance, <code>--step-5</code> corresponds to the largest font size, which you will use for main headings (<code>h1</code>), and smaller sizes like <code>--step-1</code> for text that's less prominent.</p>
<h3 id="heading-how-typography-and-spacing-work-together">How Typography and Spacing Work Together</h3>
<p>To apply these scalable values, we’ll use the following for headings:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span>,
<span class="hljs-selector-class">.h1</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--step-<span class="hljs-number">5</span>);
}

<span class="hljs-selector-tag">h2</span>,
<span class="hljs-selector-class">.h2</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--step-<span class="hljs-number">4</span>);
}

<span class="hljs-selector-tag">h3</span>,
<span class="hljs-selector-class">.h3</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--step-<span class="hljs-number">3</span>);
}

<span class="hljs-selector-tag">h4</span>,
<span class="hljs-selector-class">.h4</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--step-<span class="hljs-number">2</span>);
}

<span class="hljs-selector-tag">h5</span>,
<span class="hljs-selector-class">.h5</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">var</span>(--step-<span class="hljs-number">1</span>);
}
</code></pre>
<p>Here, the <code>h1</code> will be the largest size (using <code>--step-5</code>), and <code>h2</code> will be a little smaller (<code>--step-4</code>), continuing down to <code>h5</code>. These variables ensure the text adjusts to different screen sizes and maintains consistent visual hierarchy.</p>
<h3 id="heading-defining-constants-for-layouts-and-spacing">Defining Constants for Layouts and Spacing</h3>
<p>We can also define some utility classes and wrappers for more consistent layouts across the website. Here's how we can define some constants for layout styling:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* define some constants */</span>
<span class="hljs-selector-class">.flex</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">gap</span>: <span class="hljs-built_in">var</span>(--space-s);
}
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">468px</span>) {
  <span class="hljs-selector-class">.flex</span> {
    <span class="hljs-attribute">flex-wrap</span>: wrap;
  }
}
<span class="hljs-selector-class">.flex_center</span> {
  <span class="hljs-attribute">justify-content</span>: center;
}
<span class="hljs-selector-class">.flex_around</span> {
  <span class="hljs-attribute">justify-content</span>: space-around;
}
<span class="hljs-selector-class">.flex_between</span> {
  <span class="hljs-attribute">justify-content</span>: space-between;
}
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">468px</span>) {
  <span class="hljs-selector-class">.flex_around</span> {
    <span class="hljs-attribute">justify-content</span>: center;
  }
  <span class="hljs-selector-class">.flex_between</span> {
    <span class="hljs-attribute">justify-content</span>: center;
  }
}
<span class="hljs-selector-class">.text_center</span> {
  <span class="hljs-attribute">text-align</span>: center;
}
<span class="hljs-selector-class">.text_right</span> {
  <span class="hljs-attribute">text-align</span>: right;
}

<span class="hljs-comment">/* define spacing */</span>
<span class="hljs-selector-class">.padding-top-3xs</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--space-<span class="hljs-number">3</span>xs);
}
</code></pre>
<p>These classes allow you to quickly apply flexible layouts and spacing throughout your design. The <code>.flex</code> class will apply Flexbox, while <code>.flex_center</code> centers the content. There are also responsive adjustments for smaller screens like wrapping flex items when necessary.</p>
<h3 id="heading-creating-the-wrappers">Creating the Wrappers</h3>
<p>To help structure your layout neatly and consistently, we’ll use wrappers. Wrappers ensure that content is centered and doesn’t stretch too far on wide screens:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* create the wrappers */</span>
<span class="hljs-selector-class">.wrapper</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">1240px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
}
<span class="hljs-selector-class">.wrapper_inner</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">800px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
}
</code></pre>
<p>The <code>.wrapper</code> class ensures that the content doesn’t get too wide, while <code>.wrapper_inner</code> adds another layer of control for inner sections like a main content area or smaller containers.</p>
<h2 id="heading-how-to-build-the-header-and-hero-section">How to Build the Header and Hero Section</h2>
<p>Now that our project structure is ready, let’s get into building the first major sections: the Header and Hero. These sections are your site’s first impression, giving visitors a sense of who you are while offering easy navigation.</p>
<h3 id="heading-html-for-the-header-and-hero">HTML for the Header and Hero</h3>
<p>Here’s the HTML structure for both sections:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"styles.css"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Spruce - Dev Portfolio<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"site_header"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper_inner"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"site_header_nav"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"list"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex flex_center"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#0"</span>&gt;</span>HOME<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#about"</span>&gt;</span>ABOUT<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#work"</span>&gt;</span>WORK<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#contact"</span>&gt;</span>CONTACT<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"hero"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper_inner"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text_center hero_content"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h2"</span>&gt;</span>Spruce Emmanuel<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h5"</span>&gt;</span>WEB DEVELOPER &amp;&amp; TECHNICAL WRITER<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"list"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex flex_between hero_social"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">address</span>&gt;</span>Port Harcourt, Nigeria<span class="hljs-tag">&lt;/<span class="hljs-name">address</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"list"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Find me online<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://github.com/iamspruce"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/assets/icon-github.svg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"GitHub"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"24"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"24"</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://x.com/sprucekhalifa"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/assets/icon-twitter.svg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Twitter"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"24"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"24"</span> /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Header breakdown:</p>
<ul>
<li><p><strong>Navigation</strong>: The navbar lets users quickly jump to key sections like Home, About, Work, and Contact. It’s centered using the <code>.flex</code> and <code>.flex_center</code> classes, making it clean and accessible.</p>
</li>
<li><p><strong>Flex layout</strong>: Links are laid out horizontally using <code>.flex</code> for a smooth, modern look.</p>
</li>
</ul>
<p>Hero breakdown:</p>
<ul>
<li><p><strong>Hero content</strong>: This is where you introduce yourself. Your name and title are centered with padding to give it space and clarity.</p>
</li>
<li><p><strong>Hero social</strong>: Below your bio, we’ve added your location and social links. These are aligned with <code>.flex</code> to keep everything neat and easy to navigate.</p>
</li>
</ul>
<h3 id="heading-css-for-header-and-hero">CSS for Header and Hero</h3>
<p>Here’s the CSS to style these sections:</p>
<h4 id="heading-header-styling">Header styling:</h4>
<pre><code class="lang-css"><span class="hljs-comment">/* Style the header */</span>
<span class="hljs-selector-class">.site_header</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--space-s) <span class="hljs-number">0</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(rgba(<span class="hljs-number">26</span>, <span class="hljs-number">26</span>, <span class="hljs-number">64</span>, <span class="hljs-number">0.9</span>), <span class="hljs-built_in">rgba</span>(<span class="hljs-number">26</span>, <span class="hljs-number">26</span>, <span class="hljs-number">64</span>, <span class="hljs-number">0.9</span>));
}

<span class="hljs-selector-class">.site_header_nav</span> <span class="hljs-selector-tag">ul</span> <span class="hljs-selector-tag">li</span> <span class="hljs-selector-tag">a</span> {
  <span class="hljs-attribute">text-decoration</span>: none;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
</code></pre>
<ul>
<li><p><code>.site_header</code>: Adds padding and a dark gradient for a sleek background.</p>
</li>
<li><p><code>.site_header_nav ul li a</code>: Removes link underlines and makes the text white for a modern, bold look.</p>
</li>
</ul>
<h4 id="heading-hero-styling">Hero styling:</h4>
<pre><code class="lang-css"><span class="hljs-comment">/* Hero section styling */</span>
<span class="hljs-selector-class">.hero_content</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--space-<span class="hljs-number">3</span>xl) <span class="hljs-number">0</span>;
}

<span class="hljs-selector-class">.hero_content</span> <span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-built_in">var</span>(--space-s);
}

<span class="hljs-selector-class">.hero_social</span> {
  <span class="hljs-attribute">padding-top</span>: <span class="hljs-built_in">var</span>(--space-<span class="hljs-number">3</span>xl);
}

<span class="hljs-comment">/* General styling for the hero section */</span>
<span class="hljs-selector-tag">section</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--space-<span class="hljs-number">2</span>xl) <span class="hljs-built_in">var</span>(--space-l);
}

<span class="hljs-selector-tag">section</span><span class="hljs-selector-id">#hero</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">linear-gradient</span>(rgba(<span class="hljs-number">26</span>, <span class="hljs-number">26</span>, <span class="hljs-number">64</span>, <span class="hljs-number">0.9</span>), <span class="hljs-built_in">rgba</span>(<span class="hljs-number">26</span>, <span class="hljs-number">26</span>, <span class="hljs-number">64</span>, <span class="hljs-number">0.9</span>)),
    <span class="hljs-built_in">url</span>(<span class="hljs-string">"/assets/background_image.jpg"</span>);
  <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">4px</span>;
  <span class="hljs-attribute">background-size</span>: cover;
  <span class="hljs-attribute">background-position</span>: top;
  <span class="hljs-attribute">background-attachment</span>: scroll;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fafafa</span>;
  <span class="hljs-attribute">--color-accent</span>: <span class="hljs-number">#8a2be2</span>;
}
</code></pre>
<ul>
<li><p><code>.hero_content</code>: Adds padding to keep the content spacious.</p>
</li>
<li><p><code>.hero_social</code>: Makes room for the social media links to stand out.</p>
</li>
<li><p><code>section#hero</code>: Sets a stylish gradient background with an image, ensuring the hero section feels engaging and visually striking.</p>
</li>
</ul>
<p>Here’s what it looks like at this point:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735812582003/a755c5b5-b5b9-4bdd-9d1b-c0ff850f066d.png" alt="Portfolio after adding the hero and header sections" class="image--center mx-auto" width="2635" height="1425" loading="lazy"></p>
<h2 id="heading-how-to-build-the-about-section">How to Build the About Section</h2>
<p>The About Section lets you introduce yourself and share your professional journey, giving visitors a glimpse of who you are and what you do.</p>
<h3 id="heading-html-for-the-about-section">HTML for the About Section</h3>
<p>Here’s the HTML structure for the About Section:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"about"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text_center"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>
        I am a web developer and technical writer. I write articles on web development and programming.
      <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper_inner"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"about_content flex flex_around"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">figure</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"about_figure text_center"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200px"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200px"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/assets/user.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Developer"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"about_img"</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">figcaption</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"about_caption"</span>&gt;</span>Spruce ❤️<span class="hljs-tag">&lt;/<span class="hljs-name">figcaption</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h5"</span>&gt;</span>
          Born in Nigeria, I've spent 4+ years building with and writing about JavaScript. I help companies market their products and services through technical writing.
        <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
</code></pre>
<p>Breakdown of the About section:</p>
<ul>
<li><p><strong>Introduction</strong>: A short and clear statement about your role as a developer.</p>
</li>
<li><p><strong>About content</strong>: The profile image and bio are positioned side by side with a flex container for balance.</p>
</li>
<li><p><strong>Figure and image</strong>: The profile image is displayed within a <code>&lt;figure&gt;</code> tag, with a caption below it.</p>
</li>
<li><p><strong>Text</strong>: A brief bio explaining your background and expertise.</p>
</li>
</ul>
<h3 id="heading-css-for-the-about-section">CSS for the About Section</h3>
<p>Here’s the CSS styling for the About section:</p>
<h4 id="heading-about-section-styling">About section styling:</h4>
<pre><code class="lang-css"><span class="hljs-comment">/* About section */</span>
<span class="hljs-selector-class">.about_content</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--space-xl) <span class="hljs-number">0</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">skewX</span>(-<span class="hljs-number">10deg</span>);
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">468px</span>) {
  <span class="hljs-selector-class">.about_content</span> {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">skewX</span>(<span class="hljs-number">0deg</span>);
  }
}

<span class="hljs-selector-class">.about_figure</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--space-xl) <span class="hljs-number">0</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">4px</span> <span class="hljs-number">6px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid <span class="hljs-number">#ccc</span>;
  <span class="hljs-attribute">display</span>: inline-block;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">5px</span>;
}

<span class="hljs-selector-class">.about_img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">300px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">200px</span>;
  <span class="hljs-attribute">object-fit</span>: cover;
}

<span class="hljs-selector-class">.about_caption</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--space-<span class="hljs-number">3</span>xs) <span class="hljs-number">0</span>;
}

<span class="hljs-selector-tag">section</span><span class="hljs-selector-id">#about</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ffffff</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">--color-accent</span>: <span class="hljs-number">#ffd700</span>;
}
</code></pre>
<p>Breakdown of the CSS:</p>
<ul>
<li><p><strong>Skew effect</strong>: The <code>.about_content</code> class gives the section a dynamic look with a slight skew, which is removed on small screens.</p>
</li>
<li><p><strong>Figure styling</strong>: The profile image gets padding and a subtle box shadow to help it stand out.</p>
</li>
<li><p><strong>Image styling</strong>: The image fills the space proportionally, ensuring it doesn't distort.</p>
</li>
<li><p><strong>Caption styling</strong>: Padding around the caption provides better spacing.</p>
</li>
</ul>
<h3 id="heading-about-section-preview">About section preview:</h3>
<p>This is what your About Section will look like after applying these styles:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735812908296/509c6cf0-a8c5-448b-8bb4-a466a76a2cbe.png" alt="Portfolio after adding the About section" class="image--center mx-auto" width="2636" height="1842" loading="lazy"></p>
<h2 id="heading-how-to-build-the-work-section">How to Build the Work Section</h2>
<p>The <strong>Work Section</strong> is where you can showcase the companies or projects you’ve worked with or contributed to. This section helps to demonstrate your experience and the impact you've made, while providing visitors with visual examples of your professional background.</p>
<h3 id="heading-html-for-the-work-section">HTML for the Work Section</h3>
<p>Here’s the HTML structure for the <strong>Work Section</strong>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"work"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper_inner"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text_center"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h4</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h5"</span>&gt;</span>
        So far I've helped 20+ companies build their web presence and
        improve their technical documentation.
      <span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"list"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"work_logos flex flex_center"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/assets/logo1.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Acme Corp"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/assets/logo2.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Acme Innovations"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
            <span class="hljs-attr">src</span>=<span class="hljs-string">"/assets/logo1.png"</span>
            <span class="hljs-attr">alt</span>=<span class="hljs-string">"Acme Solutions"</span>
            <span class="hljs-attr">width</span>=<span class="hljs-string">"50"</span>
            <span class="hljs-attr">height</span>=<span class="hljs-string">"50"</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/assets/logo3.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Acme Technologies"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/assets/logo1.png"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Acme Enterprises"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
</code></pre>
<p>Breakdown of the Work section:</p>
<ul>
<li><p><strong>Introduction</strong>: The <code>&lt;h4&gt;</code> element introduces the work experience with a statement highlighting how you've helped companies with their web presence and technical documentation.</p>
</li>
<li><p><strong>Logos</strong>: The logos of the companies you've worked with are placed inside an unordered list (<code>&lt;ul&gt;</code>). Each logo is wrapped in a list item (<code>&lt;li&gt;</code>) for better structure and layout.</p>
</li>
<li><p><strong>Flexbox layout</strong>: The logos are positioned in a flexible layout using the <code>flex</code> and <code>flex_center</code> classes. This ensures that the logos are evenly spaced and centered horizontally within the section.</p>
</li>
</ul>
<h3 id="heading-css-styling-for-the-work-section">CSS Styling for the Work Section</h3>
<p>Now let’s add some style to the Work section to make it visually appealing and responsive.</p>
<h4 id="heading-work-section-styling">Work section styling:</h4>
<pre><code class="lang-css"><span class="hljs-comment">/* work section */</span>
<span class="hljs-selector-class">.work_logos</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-built_in">var</span>(--space-xl);
}

<span class="hljs-selector-tag">section</span><span class="hljs-selector-id">#work</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#87ceeb</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#0c0c0c</span>;
  <span class="hljs-attribute">--color-accent</span>: <span class="hljs-number">#2e8b57</span>;
}
</code></pre>
<h2 id="heading-how-to-build-the-contact-section-and-footer">How to Build the Contact Section and Footer</h2>
<p>The <strong>Contact Section</strong> and <strong>Footer</strong> provide a space for visitors to reach out to you and a final touch for the webpage. It’s essential to have an easy-to-use form for inquiries, along with a footer that includes your copyright information.</p>
<h3 id="heading-html-for-the-contact-section-and-footer">HTML for the Contact Section and Footer</h3>
<p>Here’s the HTML structure for the <strong>Contact Section</strong> and <strong>Footer</strong>:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"contact"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text_left"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
        Want to work together? <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        I'd love to hear from you.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper_inner"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"h3"</span>&gt;</span>Contact Me<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">action</span>=<span class="hljs-string">""</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"contact_form"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flex"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>&gt;</span>NAME<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>&gt;</span>EMAIL<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form_group"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"message"</span>&gt;</span>Message<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"message"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"message"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>SEND MESSAGE<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>


<span class="hljs-tag">&lt;<span class="hljs-name">footer</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">section</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"footer"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text_right"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span><span class="hljs-symbol">&amp;copy;</span> 2025 Spruce Emmanuel<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
</code></pre>
<p>Breakdown of the HTML:</p>
<ul>
<li><p><strong>Contact section</strong>: This section includes a welcoming text that invites users to reach out, followed by a contact form with fields for the user’s name, email, and a message.</p>
</li>
<li><p><strong>Footer</strong>: The footer includes copyright information, ensuring that visitors know who owns the content. It’s placed at the bottom of the page and gives a professional touch to the site.</p>
</li>
</ul>
<h3 id="heading-css-for-the-contact-section-and-footer">CSS for the Contact Section and Footer</h3>
<p>Now let's style the <strong>Contact Section</strong> and <strong>Footer</strong> to make them both user-friendly and visually appealing.</p>
<h4 id="heading-contact-section-styling">Contact section styling:</h4>
<pre><code class="lang-css"><span class="hljs-comment">/* contact section */</span>
<span class="hljs-selector-class">.contact_form</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.form_group</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
}

<span class="hljs-selector-tag">label</span> {
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">font-weight</span>: bold;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"text"</span>]</span>,
<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"email"</span>]</span>,
<span class="hljs-selector-tag">textarea</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#ccc</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">4px</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">2px</span> <span class="hljs-number">4px</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-selector-tag">textarea</span> {
  <span class="hljs-attribute">resize</span>: vertical;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150px</span>;
}

<span class="hljs-selector-tag">button</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"submit"</span>]</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">4px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#007bff</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-tag">button</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"submit"</span>]</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0056b3</span>;
}
</code></pre>
<h4 id="heading-footer-section-styling">Footer section styling:</h4>
<pre><code class="lang-css"><span class="hljs-comment">/* footer section */</span>
<span class="hljs-selector-tag">section</span><span class="hljs-selector-id">#footer</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-built_in">var</span>(--space-l) <span class="hljs-built_in">var</span>(--space-l);
}
</code></pre>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>And there you have it! You've just built a simple portfolio website using only HTML and CSS. You've learned how to structure your project, apply a CSS reset, and create responsive typography and layout systems that scale beautifully across different screen sizes.</p>
<p>By following this guide, you now have a portfolio that you can be proud of and share with friends, family, or potential employers. The beauty of this project is that you can continue to expand and personalize it by adding new sections, showcasing more of your work, or experimenting with JavaScript to add interactive elements.</p>
<p>If you're interested in exploring more advanced features or learning how to host your portfolio online, check out my tutorial on <a target="_blank" href="https://www.freecodecamp.org/news/host-your-first-project-on-github/">How to Host Your Project on GitHub – Explained With Examples</a>.</p>
<p>If you have any questions, feel free to find me on Twitter at <a target="_blank" href="https://x.com/sprucekhalifa">@sprucekhalifa</a>, and don’t forget to follow me for more tips and updates. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Make Learning to Code Easier by Focusing on the Fundamentals ]]>
                </title>
                <description>
                    <![CDATA[ It’s the beginning of the year again, and perhaps you’re still struggling to learn that programming language. We’ve all been there. Let me share a story from my own journey. In 2016, I thought I wasn’t cut out for programming. After months of trying ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-make-learning-to-code-easier-by-focusing-on-the-fundamentals/</link>
                <guid isPermaLink="false">6776aff4291cde01e8a6dff0</guid>
                
                    <category>
                        <![CDATA[ coding ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Programming Tips ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Beginner Developers ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Thu, 02 Jan 2025 15:25:40 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735830905235/898a0c35-3f2a-4a05-86e8-866bb99eda42.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>It’s the beginning of the year again, and perhaps you’re still struggling to learn that programming language. We’ve all been there. Let me share a story from my own journey.</p>
<p>In 2016, I thought I wasn’t cut out for programming. After months of trying and failing with my first language, I came to a conclusion: I wasn’t smart enough. I thought some people were naturally gifted, while others, like me, simply weren’t meant for programming.</p>
<p>I gave up several times, convinced I didn’t have the talent needed to succeed.</p>
<p>Fast forward to today eight years later. I’ve become proficient in several programming languages. Looking back, I realize programming doesn’t come naturally to anyone. The difference between those who seem “gifted” and those of us who struggled is simple: it’s all about having the right foundational knowledge.</p>
<p>Programming is like walking into a movie halfway through you can’t understand what’s happening because you missed the beginning. The same applies to programming. You can’t build an advanced calculator app without understanding basic data types or algorithms.</p>
<p>Here’s the truth: programming isn’t inherently difficult. Most beginners struggle because they skip key foundational steps. Without these prerequisites, programming can feel like trying to swim in the deep end without first learning how to float.</p>
<p>But don’t worry I’ve got you covered. By the end of this article, you’ll know exactly what these prerequisites are, how to develop them, and why they’re the key to making programming click for you.</p>
<h3 id="heading-heres-what-well-cover">Here’s what we’ll cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-why-programming-feels-hard-hint-its-not-about-talent">Why Programming Feels Hard – Hint: It’s Not About Talent</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-prerequisites-you-actually-need">The Prerequisites You Actually Need</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-data-structures-taking-user-input">Data Structures: Taking User Input</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-algorithms-performing-computations">Algorithms: Performing Computations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-programming-languages-displaying-the-output">Programming Languages: Displaying the Output</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-additional-skills">Additional Skills</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-right-foundations-practice-practice-practice">How to Build the Right Foundations: Practice, Practice, Practice</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
</ol>
<h2 id="heading-why-programming-feels-hard-hint-its-not-about-talent">Why Programming Feels Hard – Hint: It’s Not About Talent</h2>
<p>Let me pick up my story again. By 2018, I was becoming a confident developer. I could build basic websites, fetch data from a database using APIs, and display it on the screen. I thought I had programming figured out.</p>
<p>Then came my first job interview.</p>
<p>During the interview, I was asked a seemingly simple question: <em>“What happens when you type</em> <em>www.google.com</em> <em>into the address bar and press Enter? You have 30 minutes.”</em></p>
<p>I paused, thought for a moment, and gave my best answer. I spoke for maybe five minutes, then the interview ended.</p>
<p>Later, I Googled the question out of curiosity. What I found shocked me. The question wasn’t just about typing and entering a URL, it was about networks, servers, DNS lookups, HTTP requests, rendering engines, and more. That’s when it hit me: I had barely scratched the surface. There was so much foundational knowledge I was missing.</p>
<p>That day, I realized programming isn’t just about fetching data from a database or making a website look good. It’s about understanding the layers beneath the surface. If you're curious, I didn’t get the job. In fact, I never heard back from them. Honestly, I wouldn’t have hired me either.</p>
<p>Now, think about that interview question: Could you confidently explain what happens when you hit “Enter” on www.google.com?</p>
<p>If you’re like I was back then, probably not. But here’s the good news: If I were asked that same question today, I could speak on it for an hour. Heck, I could even write a 1,000-word article about it.</p>
<h3 id="heading-the-real-problem-isnt-talent">The Real Problem Isn’t Talent</h3>
<p>Here’s the key takeaway: programming success isn’t about talent or intelligence. If you try to learn programming without the right preparation, you’ll keep hitting a wall of frustration.</p>
<p>So, no—it’s not talent you lack. It’s preparation. And the good news? Lack of preparation is something you can fix.</p>
<h2 id="heading-the-prerequisites-you-actually-need"><strong>The Prerequisites You Actually Need</strong></h2>
<p>To understand the prerequisites, let’s take a step back and consider what a computer is actually for. At its core, the main purpose of a computer is to:</p>
<ol>
<li><p><strong>Take user input</strong>,</p>
</li>
<li><p><strong>Perform computations</strong>, and</p>
</li>
<li><p><strong>Display the output</strong>.</p>
</li>
</ol>
<p>Every piece of software or program ever developed revolves around these three tasks. As a programmer, your role is to create software that performs these functions properly.</p>
<p>To do this, you need to build your skills in a way that aligns with these tasks. This means learning about data structures and algorithms, and then diving into a programming language. Let’s dig into each of these skills more deeply.</p>
<h2 id="heading-data-structures-taking-user-input"><strong>Data Structures: Taking User Input</strong></h2>
<p>So, users interact with your software, whether they’re clicking buttons, filling out forms, or uploading files. And guess what? All that interaction creates data that you, the developer, need to manage. But how do you do that without going crazy? That’s where <strong>data structures</strong> come in.</p>
<h3 id="heading-what-are-data-structures"><strong>What Are Data Structures?</strong></h3>
<p>Think of data structures like special containers for your data. But not just any containers – they’re the kind that let you quickly grab, change, and organize your data in the most efficient way possible. Without them, managing user input would be like trying to store your clothes in a messy pile rather than a neat closet. Not fun, right?</p>
<h3 id="heading-a-few-data-structures-you-should-know"><strong>A Few Data Structures You Should Know</strong></h3>
<p>There are tons of data structures out there, but let’s talk about a couple that are absolute essentials:</p>
<p><strong>1. Arrays</strong></p>
<p>Arrays are like simple, ordered lists. Imagine a row of boxes, each labeled with a number (index). You can put something in each box, and when you want to grab something, you just tell the system the number of the box. Super easy! It’s like a list of your favorite songs, where each song is numbered in order.</p>
<p><strong>2. Hash Tables (or Dictionaries)</strong></p>
<p>Hash tables are the cool kids of the data structure world. Instead of organizing data by number, they let you organize it by keys, which are like labels that help you find things super fast. If you had a list of customers, you could use their customer IDs as the “key” to look up their info. Think of it like a phone book—rather than flipping through pages, you jump straight to the person’s name based on how the names are organized (likely alphabetically).</p>
<h3 id="heading-why-should-you-care-about-data-structures"><strong>Why Should You Care About Data Structures?</strong></h3>
<p>Good question! Here’s the deal: first of all, data structures help you organize your data in an intelligent way that makes sense. They keep things neat and make them easy to access. No more digging through a pile of data.</p>
<p>Second, data structures can make your apps faster. With the right data structure, you’ll be able to retrieve, modify, and sort data in the blink of an eye.</p>
<p>And finally, they help you solve problems like a boss**.** Whether you need to sort stuff, search through a lot of data, or handle some complex information, data structures are your go-to solution.</p>
<h3 id="heading-example-storing-and-finding-customer-names"><strong>Example: Storing and Finding Customer Names</strong></h3>
<p>Okay, let’s say your app needs to store and retrieve customer names. You could do this in two ways. Let’s compare how an <strong>array</strong> and a <strong>hash table</strong> would handle this task.</p>
<p><strong>1. Using an Array:</strong><br>Imagine you’ve got a list of customer names, and they’re stored in a nice, neat array:</p>
<pre><code class="lang-text">customers = ["John", "Jane", "Emily", "Michael"]
</code></pre>
<p>If you want to grab the name of the person in the third spot (Emily), you can just point to the third index like this:</p>
<pre><code class="lang-text">print(customers[2])  // Output: Emily
</code></pre>
<p>Arrays are perfect if you have a simple, ordered list and you need to grab items by their position.</p>
<p><strong>2. Using a Hash Table:</strong><br>Now, let’s say you want to store customer names but also have a unique ID for each one. This is where a hash table (or dictionary) comes in handy. You use <strong>keys</strong> (like customer IDs) to quickly find their names. It’s much faster than searching through an array.</p>
<p>Here’s what it might look like in action:</p>
<pre><code class="lang-text">customers = { 101: "John", 102: "Jane", 103: "Emily", 104: "Michael" }
</code></pre>
<p>Now, if you want to find the customer with ID <code>103</code> (Emily), you just look up the key:</p>
<pre><code class="lang-text">print(customers[103])  // Output: Emily
</code></pre>
<p>Hash tables are awesome when you need to look things up fast. No searching, just straight to the point!</p>
<h3 id="heading-ready-to-dive-deeper"><strong>Ready to Dive Deeper?</strong></h3>
<p>If you're pumped to learn more about data structures, here are some resources to help you level up:</p>
<ul>
<li><p><a target="_blank" href="https://developers.google.com/learn">Google’s Data Structures Learning Guide</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/learn">freeCodeCamp’s Data Structures and Algorithms Course</a></p>
</li>
</ul>
<h2 id="heading-algorithms-performing-computations"><strong>Algorithms: Performing Computations</strong></h2>
<p>Okay, so you've got your data. Now what? Well, you need to process it—and that’s where <strong>algorithms</strong> step in. Think of algorithms as a set of instructions, kind of like a recipe, that tells your computer how to solve a problem or complete a task, step-by-step.</p>
<h3 id="heading-why-learn-algorithms-before-you-learn-a-programming-language"><strong>Why Learn Algorithms Before You Learn a Programming Language?</strong></h3>
<p>Before you dive into learning a programming language, it helps to first learn <strong>algorithms</strong>. Here’s why: algorithms teach you how to think like a problem-solver. They help you break down challenges, think logically, and tackle them systematically. And when you know your algorithms, you’re not just memorizing syntax – you’re also learning <strong>how to solve problems efficiently</strong>. That makes programming a lot easier.</p>
<h3 id="heading-lets-dive-into-some-cool-algorithms"><strong>Let’s Dive Into Some Cool Algorithms</strong></h3>
<p>There are a ton of algorithms out there, but let’s keep it simple for now with a couple of the most popular ones. These will get you started and make your code run smoother than ever.</p>
<h4 id="heading-1-bubble-sort-the-basics-of-sorting"><strong>1. Bubble Sort: The Basics of Sorting</strong></h4>
<p>Bubble Sort is the beginner’s go-to algorithm for sorting. It’s simple—kinda like flipping pancakes. You start with the first two elements in the list, compare them, and if they’re in the wrong order, you swap them. Then you move to the next pair and keep doing that until everything is in order.</p>
<p>Here’s how it works:</p>
<p>Imagine you’ve got a list of names that need to be sorted alphabetically:</p>
<pre><code class="lang-plaintext">John, Sarah, Anna, Jake, Emily
</code></pre>
<p>Bubble Sort will go through the list, comparing two names at a time, swapping them if they’re out of order. It repeats this process until the list is sorted.</p>
<p>At the end, your list will look like this:</p>
<pre><code class="lang-plaintext">Anna, Emily, Jake, John, Sarah
</code></pre>
<p>It’s simple, but not the fastest for long lists.</p>
<h4 id="heading-2-quick-sort-speedy-and-smart"><strong>2. Quick Sort: Speedy and Smart</strong></h4>
<p>If Bubble Sort is like a slow and steady turtle, Quick Sort is the speedy rabbit. It’s much faster, especially for larger data sets. Quick Sort is a “divide and conquer” algorithm—it breaks the list into smaller chunks, sorts them, and then puts everything back together.</p>
<p>Here’s how it works:</p>
<p>Let’s take that same list of names and use Quick Sort:</p>
<pre><code class="lang-plaintext">John, Sarah, Anna, Jake, Emily
</code></pre>
<p>First, pick a <strong>pivot</strong>—let’s say <strong>Jake</strong>. Now, split the list into two parts:</p>
<ul>
<li><p>Names that come <strong>before Jake</strong> alphabetically:</p>
<pre><code class="lang-plaintext">  Anna, Emily
</code></pre>
</li>
<li><p>Names that come <strong>after Jake</strong> alphabetically:</p>
<pre><code class="lang-plaintext">  John, Sarah
</code></pre>
</li>
</ul>
<p>Now, you repeat the process for each group. Keep picking pivots, splitting, and sorting until each group is small enough to be sorted easily. Then you just put everything back together, and voilà! Sorted list:</p>
<pre><code class="lang-bash">Anna, Emily, Jake, John, Sarah
</code></pre>
<p>Quick Sort is much faster than Bubble Sort, especially when you've got a lot of names to sort.</p>
<p>Again, there are many more algorithms to learn, but this should give you the basic idea of how they work and why they’re useful.</p>
<h3 id="heading-why-you-should-care-about-algorithms"><strong>Why You Should Care About Algorithms</strong></h3>
<p>So why does any of this matter? Here’s the deal: first, algorithms help you solve problems more easily by breaking them down problems into manageable steps.</p>
<p>Second, they make your code faster. With the right algorithm, you can make your code run like a sports car—fast!</p>
<p>They also allow you to manage big datasets more easily. Some algorithms, like Quick Sort, can handle large sets of data in no time, which is crucial when performance matters.</p>
<h3 id="heading-want-to-get-better-at-algorithms"><strong>Want to Get Better at Algorithms?</strong></h3>
<p>If you’re hungry for more algorithmic goodness, here’s where to go:</p>
<ul>
<li><p><a target="_blank" href="https://leetcode.com/">LeetCode</a></p>
</li>
<li><p><a target="_blank" href="https://www.hackerrank.com/">HackerRank</a></p>
</li>
</ul>
<p>And if you want to dive deeper, <a target="_blank" href="https://www.freecodecamp.org/news/learn-data-structures-and-algorithms-2/">here’s a free 48-hour course on the freeCodeCamp YouTube channel</a> on Data Structures and Algorithms.</p>
<h2 id="heading-programming-languages-displaying-the-output"><strong>Programming Languages: Displaying the Output</strong></h2>
<p>Finally, we get to programming languages. This is where most beginners start and it’s often why they struggle. Without a solid grasp of data structures and algorithms, programming languages can feel like trying to run before you can walk. You can learn the syntax, but without understanding the fundamentals, you’ll find it harder to write effective code.</p>
<h3 id="heading-why-programming-languages-should-come-last"><strong>Why Programming Languages Should Come Last:</strong></h3>
<p>Once you understand how to manage input (data structures) and process it (algorithms), learning a programming language becomes much easier. You can go beyond worrying about memorizing syntax you may not understand, and start applying logic and solving problems. Programming languages are the tools you use to implement your algorithms and data structures.</p>
<h3 id="heading-which-programming-language-to-learn"><strong>Which Programming Language to Learn:</strong></h3>
<p>When it comes to picking a programming language, it’s important to align your choice with your goals. The language you choose should be based on what you want to build and your career path.</p>
<p>Here’s a breakdown of some common choices:</p>
<ul>
<li><p><strong>JavaScript</strong>: If your goal is to build websites or web applications, JavaScript is essential. It runs in the browser and allows you to create dynamic and interactive websites. JavaScript also has a wide range of libraries and frameworks (like React, Node.js, and Vue) that can speed up development.</p>
</li>
<li><p><strong>Python</strong>: Known for its simplicity and readability, Python is a great choice for beginners. It’s widely used in data science, web development (with frameworks like Django and Flask), and machine learning. Python's syntax is clean and easy to understand, which makes it perfect for beginners focusing on building strong foundational skills.</p>
</li>
<li><p><strong>Java</strong>: If you’re interested in building large-scale, enterprise-level applications, Java is a solid choice. It's a statically typed language, meaning you define variable types explicitly. Java is commonly used in Android development and large backend systems.</p>
</li>
<li><p><strong>Swift</strong>: Swift is a great language for iOS app development. If you want to build mobile apps for the Apple ecosystem (iPhone, iPad, etc.), Swift is the way to go. It's fast, modern, and integrates well with Apple’s software development tools.</p>
</li>
<li><p><strong>C#</strong>: If you’re planning to work with game development, especially with Unity, C# is your best bet. It’s also used for enterprise applications, web development (via ASP.NET), and desktop apps.</p>
</li>
</ul>
<h3 id="heading-how-to-choose-the-right-language-for-you"><strong>How to Choose the Right Language for You:</strong></h3>
<p>The best way to choose a language is to consider what excites you and where you want to focus your efforts. Don’t worry too much about finding the "easiest" language – just focus on one that aligns with your interests.</p>
<p>For example, if you're excited about building websites, JavaScript might be the best place to start. If you’re interested in mobile apps, Swift or Kotlin could be a better fit.</p>
<p>Once you've picked a language, don’t stress about mastering every feature. Start with the basics and build projects that interest you. As you practice, you’ll naturally pick up more advanced concepts and techniques. The goal isn’t to become a master of syntax but to learn how to think like a programmer and solve problems effectively.</p>
<p><strong>Here are some tips for getting started:</strong></p>
<ol>
<li><p><strong>Start with Basics</strong>: Get comfortable with basic syntax and constructs. Learn how to write loops, conditional statements, and functions in your chosen language.</p>
</li>
<li><p><strong>Build Simple Projects</strong>: Apply what you've learned by building small projects. If you're learning JavaScript or Python, for example, try building a simple to-do list app or a calculator. These types of projects help solidify your understanding.</p>
</li>
<li><p><strong>Understand Libraries and Frameworks</strong>: Once you have the basics down, dive into libraries and frameworks that can help speed up development. For JavaScript, this might mean learning React or Vue. For Python, it could mean exploring Django or Flask.</p>
</li>
</ol>
<p><strong>Helpful Resources for Learning Programming Languages</strong>:</p>
<ul>
<li><p><a target="_blank" href="http://JavaScript.info">JavaScript.info</a></p>
</li>
<li><p><a target="_blank" href="http://Python.org">Python.org</a> <a target="_blank" href="https://docs.python.org/3/tutorial/">Tutorials</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/learn/">freeCodeCamp JavaScript Curriculum</a></p>
</li>
<li><p><a target="_blank" href="https://www.codecademy.com/learn/learn-python-3">Codecademy Python</a></p>
</li>
</ul>
<h2 id="heading-additional-skills"><strong>Additional Skills</strong></h2>
<p>While mastering the fundamentals of programming is essential, there are other skills that can significantly boost your development journey. These include problem-solving techniques, debugging, and version control. These skills might not seem as glamorous as learning a programming language, but they are just as important.</p>
<h3 id="heading-why-these-skills-matter"><strong>Why These Skills Matter:</strong></h3>
<p>Even if you know the syntax of a language, you’ll still face challenges when writing real-world applications. Problems like bugs, performance issues, and collaboration with other developers are inevitable. That’s why these additional skills are so valuable as they help you tackle these challenges more effectively.</p>
<p><strong>1. Problem-Solving:</strong><br>Problem-solving is at the core of programming. It’s not enough to know how to write code – you also need to know how to break down a problem and figure out the best way to solve it. A good programmer typically spends just as much time thinking about the problem as they do writing the solution.</p>
<ul>
<li><p><strong>Breaking down the problem</strong>: Start by understanding the problem. Ask questions like: What am I trying to achieve? What do I already know? What inputs do I have, and what do I expect as the output?</p>
</li>
<li><p><strong>Dividing it into smaller parts</strong>: Once you have a clear understanding, divide the problem into smaller, manageable pieces. This helps you focus on solving one part at a time rather than feeling overwhelmed by the entire issue.</p>
</li>
<li><p><strong>Looking for patterns</strong>: Often, problems in programming can be solved by recognizing patterns or using similar approaches you’ve learned before. Don’t be afraid to reuse code you’ve written or adapt it for a new task.</p>
</li>
</ul>
<p><strong>2. Debugging:</strong> No code is perfect, and bugs are inevitable. Debugging is the process of finding and fixing these bugs (problems in your code that cause it to mess up or not run). It's a skill that every programmer needs to learn because it helps you maintain and improve the quality of your code.</p>
<ul>
<li><p><strong>Using print statements</strong>: A simple and effective debugging technique is inserting print statements (or logging) in your code. This allows you to inspect variables and understand what’s happening at different stages of your program.</p>
</li>
<li><p><strong>Using a debugger</strong>: A debugger is a tool that allows you to step through your code line by line. It’s especially helpful when dealing with more complex bugs. Many programming environments, like Visual Studio Code or PyCharm, have built-in debuggers.</p>
</li>
<li><p><strong>Checking for common issues</strong>: Bugs often come from simple issues like typos, off-by-one errors, or misunderstanding the behavior of a function. Before diving into complex debugging, double-check your assumptions.</p>
</li>
</ul>
<p><strong>3. Version Control:</strong> Version control is a tool that helps developers manage changes to their code over time. It allows you to keep track of edits, collaborate with others, and revert to previous versions if something goes wrong.</p>
<ul>
<li><p><strong>Git</strong>: Git is the most widely used version control system. It allows you to save snapshots of your code, known as commits, and track the history of your project. It also makes collaboration easier by allowing multiple developers to work on the same project without stepping on each other's toes.</p>
</li>
<li><p><strong>GitHub</strong>: GitHub is a platform that hosts Git repositories and offers additional tools like issue tracking, project management, and code reviews. As you start collaborating with other developers, GitHub will become an invaluable resource.</p>
</li>
<li><p><strong>Basic Git commands</strong>: Learn basic Git commands like <code>git init</code>, <code>git commit</code>, <code>git push</code>, and <code>git pull</code>. Understanding these commands will allow you to manage your code effectively, both when working solo and with a team.</p>
</li>
</ul>
<p><strong>Helpful Resources for Additional Skills:</strong></p>
<ul>
<li><p><a target="_blank" href="https://leetcode.com/">LeetCode</a> (for problem-solving practice)</p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/debugging-tips/">freeCodeCamp Debugging Guide</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/gitting-things-done-book/">Book on Learning Git and GitHub</a></p>
</li>
<li><p><a target="_blank" href="https://git-scm.com/doc">Git Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://guides.github.com/">GitHub Guides</a></p>
</li>
</ul>
<h2 id="heading-how-to-build-the-right-foundations-practice-practice-practice"><strong>How to Build the Right Foundations: Practice, Practice, Practice</strong></h2>
<p>Okay, so you've got the theory down, but the real magic happens when you put what you've learned into action. Mastering data structures and algorithms isn't just about understanding them it’s about <strong>practicing</strong> until they feel second nature. Here’s how you can do that:</p>
<h3 id="heading-start-small-learn-the-basics"><strong>Start Small: Learn the Basics</strong></h3>
<p>Before you dive into big, complex problems, start by getting comfortable with the basics. Things like arrays, stacks, and queues are your best friends.</p>
<p><strong>Example Practice</strong>:<br>Start with problems that help you understand how these data structures work. Try writing a function that <strong>reverses a string</strong> using a stack. Here's a quick idea of what that might look like in JavaScript:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">reverseString</span>(<span class="hljs-params">inputString</span>) </span>{
    <span class="hljs-keyword">let</span> stack = [];
    <span class="hljs-comment">// Push all characters onto the stack</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; inputString.length; i++) {
        stack.push(inputString[i]);
    }

    <span class="hljs-keyword">let</span> reversedString = <span class="hljs-string">''</span>;
    <span class="hljs-comment">// Pop characters off the stack and add them to reversedString</span>
    <span class="hljs-keyword">while</span> (stack.length &gt; <span class="hljs-number">0</span>) {
        reversedString += stack.pop();
    }

    <span class="hljs-keyword">return</span> reversedString;
}

<span class="hljs-built_in">console</span>.log(reverseString(<span class="hljs-string">"hello"</span>));  <span class="hljs-comment">// Output: "olleh"</span>
</code></pre>
<p><strong>Why this helps</strong>: By using a stack to reverse a string, you're getting a hands-on feel for how stacks work—storing items and then removing them in reverse order. Practice small problems like this daily.</p>
<h3 id="heading-solve-real-problems-bring-algorithms-to-life"><strong>Solve Real Problems: Bring Algorithms to Life</strong></h3>
<p>Once you’ve nailed the basics, it’s time to apply what you've learned in real-world scenarios. Try using algorithms to solve problems that feel useful in real life.</p>
<p><strong>Example Practice</strong>:<br>Create a simple <strong>sorting program</strong> to arrange names alphabetically using an algorithm like <strong>Bubble Sort</strong> or <strong>Quick Sort</strong>. Here’s a quick example using Bubble Sort:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bubbleSort</span>(<span class="hljs-params">names</span>) </span>{
    <span class="hljs-keyword">let</span> n = names.length;
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; n; i++) {
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> j = <span class="hljs-number">0</span>; j &lt; n - i - <span class="hljs-number">1</span>; j++) {
            <span class="hljs-keyword">if</span> (names[j] &gt; names[j + <span class="hljs-number">1</span>]) {
                <span class="hljs-keyword">let</span> temp = names[j];
                names[j] = names[j + <span class="hljs-number">1</span>];
                names[j + <span class="hljs-number">1</span>] = temp;
            }
        }
    }
    <span class="hljs-keyword">return</span> names;
}

<span class="hljs-keyword">let</span> names = [<span class="hljs-string">"John"</span>, <span class="hljs-string">"Emily"</span>, <span class="hljs-string">"Sarah"</span>, <span class="hljs-string">"Jake"</span>];
<span class="hljs-built_in">console</span>.log(bubbleSort(names));  <span class="hljs-comment">// Output: ['Emily', 'Jake', 'John', 'Sarah']</span>
</code></pre>
<p><strong>Why this helps</strong>: Solving real problems with algorithms deepens your understanding and gives you a tangible result. Whether you’re sorting names or calculating averages, real problems make the learning experience stick.</p>
<h3 id="heading-write-code-daily-make-it-a-habit"><strong>Write Code Daily: Make It a Habit</strong></h3>
<p>The secret to becoming a great programmer is consistency. Choose a programming language (Python, JavaScript, Java, or whatever you like) and make it a habit to write code <strong>every day</strong>. Even if it's just for 30 minutes, those 30 minutes add up.</p>
<p><strong>Example Practice</strong>:<br>Pick a small problem every day to practice applying data structures and algorithms. Use platforms like <a target="_blank" href="https://leetcode.com/">LeetCode</a> or <a target="_blank" href="https://www.hackerrank.com/">HackerRank</a> for daily challenges that fit your skill level. Here’s an example of a coding challenge you might find on these platforms:</p>
<ul>
<li><p><strong>Problem</strong>: Find the maximum number in a list of integers.</p>
<pre><code class="lang-javascript">  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">findMax</span>(<span class="hljs-params">nums</span>) </span>{
      <span class="hljs-keyword">let</span> maxNum = nums[<span class="hljs-number">0</span>];
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> num <span class="hljs-keyword">of</span> nums) {
          <span class="hljs-keyword">if</span> (num &gt; maxNum) {
              maxNum = num;
          }
      }
      <span class="hljs-keyword">return</span> maxNum;
  }

  <span class="hljs-built_in">console</span>.log(findMax([<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">7</span>, <span class="hljs-number">0</span>, <span class="hljs-number">-5</span>]));  <span class="hljs-comment">// Output: 7</span>
</code></pre>
</li>
</ul>
<p><strong>Why this helps</strong>: Daily practice is key to internalizing what you’ve learned. It helps you stay sharp and gradually move from simple problems to more complex ones.</p>
<h3 id="heading-challenge-yourself-go-beyond-your-comfort-zone"><strong>Challenge Yourself: Go Beyond Your Comfort Zone</strong></h3>
<p>When you feel like you’ve got the basics down, it’s time to <strong>level up</strong>. Get involved in coding challenges or take on personal projects that push you outside of your comfort zone.</p>
<p><strong>Example Practice</strong>:<br>Join a hackathon or participate in a competitive coding challenge like <a target="_blank" href="https://codingcompetitions.withgoogle.com/">Google Code Jam</a> or <a target="_blank" href="https://codeforces.com/">Codeforces</a>. These challenges will push your problem-solving skills to the limit and help you learn new algorithms and techniques.</p>
<p><strong>Why this helps</strong>: Challenges force you to think critically and solve problems under time constraints. They help you learn faster and build confidence in your abilities.</p>
<h3 id="heading-stay-consistent-build-a-routine"><strong>Stay Consistent: Build a Routine</strong></h3>
<p>Consistency is the key to success in programming (and in most things, really). Set aside time every day or week to practice. Even if you don’t feel like it, just getting in some short coding sessions will make a huge difference in the long run.</p>
<p><strong>Example Practice</strong>:<br>Create a study plan with weekly goals. For example:</p>
<ul>
<li><p><strong>Week 1</strong>: Focus on basic data structures (arrays, stacks, queues).</p>
</li>
<li><p><strong>Week 2</strong>: Move on to sorting algorithms (Bubble Sort, Merge Sort).</p>
</li>
<li><p><strong>Week 3</strong>: Dive into more complex algorithms like Binary Search or Dynamic Programming.</p>
</li>
</ul>
<p>A routine ensures that you’re making steady progress. Plus, it makes sure you don’t get stuck on one topic for too long.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Programming doesn’t have to be so hard. It’s like building a house: without a strong foundation, everything else feels unstable. But with the right basics like data structures, algorithms, and logical thinking, you’ll be amazed at how quickly you can create great things.</p>
<p>If someone had told me in 2016 that I’d be writing this article today, I wouldn’t have believed them. But with the right preparation, I turned frustration into confidence, and so can you.</p>
<p>Don’t let frustration hold you back. Focus on the fundamentals, practice consistently, and explore the resources I’ve shared. Remember, programming isn’t about being a genius it’s about preparation and persistence. You’ve got this!</p>
<p>If you have any questions, feel free to find me on Twitter at <a target="_blank" href="https://x.com/sprucekhalifa">@sprucekhalifa</a>, and don’t forget to follow me for more tips and updates. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How To Create a Progressive Web App (PWA) Using Next.js ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever wanted to create a web app that works smoothly on any device—whether it's on the web, mobile, or desktop? Imagine if your app could load quickly, work without an internet connection, and feel like a native app, all without needing to be... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-a-nextjs-pwa/</link>
                <guid isPermaLink="false">66ededaa06a4bf699b266b23</guid>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PWA ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Fri, 20 Sep 2024 21:48:26 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1726728761614/ba739b83-78b9-4cd7-9040-13ade8e515f7.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever wanted to create a web app that works smoothly on any device—whether it's on the web, mobile, or desktop? Imagine if your app could load quickly, work without an internet connection, and feel like a native app, all without needing to be installed from an app store. That’s exactly what Progressive Web Apps (PWAs) can do.</p>
<p>In this tutorial, you’ll learn how to build a PWA using Next.js. We’ll start by creating a functional movie search website with these tools. Once we have the basics set up, we’ll transform this app into a PWA, adding offline support and faster load times. By the end, you’ll have a powerful PWA that offers a smooth user experience across all platforms—all from a single codebase.</p>
<h3 id="heading-what-well-cover"><strong>What We’ll Cover</strong></h3>
<ul>
<li><p><strong>Setting Up the Project:</strong> We'll begin by creating the movie search app using Next.js, which is an ideal choice in 2024 for building fast, reliable React apps that work well on all devices.</p>
</li>
<li><p><strong>Turning the App into a PWA:</strong> Next, we’ll walk through the steps to convert the app into a Progressive Web App, covering the key features and best practices of PWAs.</p>
</li>
<li><p><strong>Adding Offline Support:</strong> Finally, we’ll ensure your app stays functional even when there’s no internet connection by implementing offline capabilities.</p>
</li>
</ul>
<p>Here’s what the final application will look like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726724446891/47398ad8-fa1f-46d2-8a22-0a5d49e6a67e.png" alt="This screenshot shows the completed MovieMaster PWA, highlighting its sleek design and offline capabilities." class="image--center mx-auto" width="2624" height="1754" loading="lazy"></p>
<h3 id="heading-audience"><strong>Audience</strong></h3>
<p>This tutorial is for React developers of all levels, whether you’re just starting out or already experienced. If you want to enhance your web apps with PWA features, this guide will take you through the necessary steps.</p>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>Before you begin, make sure you’re familiar with React.js and Next.js. If you’re new to PWAs, you might want to read some introductory articles to get a quick overview.</p>
<ul>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/what-are-progressive-web-apps-pwa-guide/"><em>What are Progressive Web Apps? PWA Guide for Beginners</em></a></p>
</li>
<li><p><a target="_blank" href="https://web.dev/learn/pwa"><em>Learn Progressive Web Apps</em></a></p>
</li>
</ul>
<aside>
  <h2 id="heading-table-of-contents">Table of Contents</h2>
  <ul>
    <li><a href="#0">Introduction</a></li>
    <li><a href="#heading-what-we-cover">What We’ll Cover</a></li>
    <li><a href="#heading-audience">Audience</a></li>
    <li><a href="#heading-prerequisites">Prerequisites</a></li>
    <li><a href="#heading-what-is-a-progressive-web-app-pwa">What is a Progressive Web App (PWA)?</a></li>
    <li><a href="#heading-why-turn-your-web-app-into-a-pwa">Why Turn Your Web App into a PWA?</a></li>
    <li><a href="#heading-getting-started-setting-up-the-nextjs-project">Getting Started: Setting Up the Next.js Project</a></li>
    <li><a href="#heading-why-choose-nextjs-in-2024">Why Choose Next.js in 2024?</a></li>
    <li><a href="#heading-project-installation">Project Installation</a></li>
    <li><a href="#heading-project-structure-overview">Project Structure Overview</a></li>
 <li><a href="#heading-understanding-layouts">Understanding Layouts</a></li>
    <li><a href="#heading-running-and-previewing-the-project">Running and Previewing the Project</a></li>
    <li><a href="#heading-how-to-turn-your-web-app-into-a-pwa">How to Turn Your Web App into a PWA</a></li>
    <li><a href="#heading-criteria-for-a-pwa">Criteria for a PWA</a></li>
    <li><a href="#heading-how-to-add-a-web-manifest-file-to-your-nextjs-app">How to Add a Web Manifest File to Your Next.js App</a></li>
    <li><a href="#heading-how-to-register-a-service-worker">How to Register a Service Worker</a></li>
    <li><a href="#heading-how-to-add-offline-support">How to Add Offline Support</a></li>
    <li><a href="#heading-what-to-cache">What to Cache?</a></li>
    <li><a href="#heading-when-to-cache">When to Cache?</a></li>
    <li><a href="#heading-dynamic-caching">Dynamic Caching</a></li>
    <li><a href="#heading-caching-api-requests">Caching API Requests</a></li>
    <li><a href="#heading-how-to-serve-cached-resources">How to Serve Cached Resources</a></li>
    <li><a href="#heading-providing-a-fallback-page">Providing a Fallback Page</a></li>
    <li><a href="#heading-conclusion">Conclusion</a></li>
  </ul>
</aside>

<h2 id="heading-what-is-a-progressive-web-app-pwa">What is a Progressive Web App (PWA)?</h2>
<p>A Progressive Web App (PWA) is a type of web application built using standard web technologies like HTML, CSS, and JavaScript. PWAs work on the web, desktop, and mobile devices, combining the best features of web and native apps to deliver a fast, reliable, and engaging experience.</p>
<p>What makes PWAs special is their ability to work offline, send push notifications, and be installed on a user’s device without an app store. In short, a PWA makes your web app feel like a native app while keeping the flexibility and wide reach of the web.</p>
<h3 id="heading-why-turn-your-web-app-into-a-pwa"><strong>Why Turn Your Web App into a PWA?</strong></h3>
<p>Converting your web app into a PWA brings several benefits:</p>
<ul>
<li><strong>Cross-Platform Availability:</strong> A PWA works on any device with a browser, so you only need to develop and maintain one codebase for web, mobile, and desktop apps. This saves time and ensures a consistent experience across all platforms.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726724668376/acf531ba-7ff7-4c62-8d11-ac283d236bd8.png" alt="This image shows the MovieMaster PWA running on a mobile phone, web browser, and desktop, showcasing the versatile nature of PWAs." width="1600" height="661" loading="lazy"></p>
<ul>
<li><p><strong>Offline Capabilities:</strong> PWAs can work offline or in areas with poor connectivity by caching essential resources, keeping your app functional even without internet access.</p>
</li>
<li><p><strong>Improved Performance:</strong> PWAs are built to load quickly and run smoothly, even on slow networks, thanks to techniques like service workers and caching.</p>
</li>
<li><p><strong>Increased User Engagement:</strong> Users can add PWAs directly to their home screen without needing an app store. This easy access, along with features like push notifications, helps keep users engaged and coming back.</p>
</li>
</ul>
<p><strong>Disadvantages of PWAs</strong></p>
<p>While PWAs offer many benefits, there are a few downsides:</p>
<ul>
<li><p><strong>Limited Access to Device Features</strong>: PWAs don’t have full access to certain device features like Bluetooth or advanced camera controls. For apps that need deep hardware integration, this can be a limitation.</p>
</li>
<li><p><strong>Less Visibility</strong>: Since PWAs don’t go through app stores, they miss out on the visibility that app stores offer. Some users might also prefer downloading apps from app stores rather than directly from the browser.</p>
</li>
<li><p><strong>Limited iOS Support</strong>: Some features of PWAs, like push notifications, don’t work as well on iPhones and iPads compared to Android devices, which can limit engagement with iOS users.</p>
</li>
</ul>
<h2 id="heading-getting-started-setting-up-the-nextjs-project"><strong>Getting Started: Setting Up the Next.js Project</strong></h2>
<p>Now that we’ve talked about the benefits of PWAs, let’s get into the actual implementation. We’ll start by setting up the necessary files in our project.</p>
<h3 id="heading-why-choose-nextjs-in-2024"><strong>Why Choose Next.js in 2024?</strong></h3>
<p>Next.js is a top choice for building React apps in 2024. It offers features like server-side rendering and static site generation, making it easier to create fast and reliable web apps. These features ensure your app performs well on all devices and even works offline.</p>
<h3 id="heading-project-installation"><strong>Project Installation</strong></h3>
<p>Follow these steps to set up your Next.js project:</p>
<ol>
<li><p>Clone the Repository: Open your terminal and run:</p>
<pre><code class="lang-bash"> git <span class="hljs-built_in">clone</span> https://github.com/iamspruce/MovieMaster.git
</code></pre>
</li>
<li><p>Navigate to Your Project Directory:</p>
<pre><code class="lang-bash"> <span class="hljs-built_in">cd</span> your-repo
</code></pre>
</li>
<li><p>Install Dependencies: Install the required packages with:</p>
<pre><code class="lang-bash"> npm install
</code></pre>
</li>
<li><p>Configure Environment Variables: Create a .env.local file in the root directory and add your OMDB API key:</p>
<pre><code class="lang-plaintext"> NEXT_PUBLIC_OMDB_API_KEY=your-api-key
</code></pre>
</li>
</ol>
<p>You can obtain your API key from the <a target="_blank" href="https://www.omdbapi.com/apikey.aspx">OMDB API website</a>.</p>
<p><strong>Why is the OMDB API Key Needed?</strong><br>The OMDB API key allows your PWA to fetch movie data, like titles, posters, and descriptions, directly from the OMDB database. This is essential for a movie-related app like MovieMaster, as it provides up-to-date information for users without you having to store all the data yourself.</p>
<p>In a PWA, using an API like OMDB ensures that the app can deliver fresh content to users, even when it's installed on their devices. Combined with the PWA's caching and offline features, users can still view movie details that were previously fetched, even if they lose internet connectivity.</p>
<p><strong>Note</strong>: Make sure Node.js and npm are installed on your system. If they are not, you can download them from <a target="_blank" href="http://nodejs.org/">nodejs.org</a>.</p>
<h4 id="heading-project-structure-overview"><strong>Project Structure Overview</strong></h4>
<p>Here’s a brief overview of the project layout:</p>
<ul>
<li><p><strong>/public</strong>: Contains static files such as images and favicons.</p>
</li>
<li><p><strong>/src/app</strong>: Houses the main application files, including global styles (globals.css), the main page (<strong>page.tsx</strong>), layout configurations (<strong>layout.tsx</strong>), and client-side logic (<strong>RootLayoutClient.tsx</strong>).</p>
</li>
<li><p><strong>/src/components</strong>: Includes reusable components. Shadcn UI components are located in the /ui directory, and other specific components like <strong>MovieCard.tsx</strong> are here.</p>
</li>
<li><p><strong>/src/lib</strong>: Contains utility functions and data-fetching code, such as <strong>fetchMovies.ts</strong> and <strong>useMediaQuery.ts</strong>.</p>
</li>
</ul>
<p>For styling, we use:</p>
<ul>
<li><p><strong>TailwindCSS</strong>: Applied through <strong>globals.css</strong> for a utility-first approach to design.</p>
</li>
<li><p><strong>Shadcn UI</strong>: A library providing accessible, ready-to-use UI components.</p>
</li>
</ul>
<h4 id="heading-understanding-layouts"><strong>Understanding Layouts</strong></h4>
<p>The project uses two key layouts:</p>
<ol>
<li><p><strong>layout.tsx</strong>: Manages server-side rendering and sets the application’s metadata. It uses the <code>RootLayoutClient</code> component to handle client-side functionality. Here’s how it looks:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
 <span class="hljs-keyword">import</span> type { Metadata } <span class="hljs-keyword">from</span> <span class="hljs-string">"next"</span>;
 <span class="hljs-keyword">import</span> { cn } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/lib/utils"</span>;
 <span class="hljs-keyword">import</span> { Inter <span class="hljs-keyword">as</span> FontSans } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/font/google"</span>;

 <span class="hljs-keyword">import</span> RootLayoutClient <span class="hljs-keyword">from</span> <span class="hljs-string">"./RootLayoutClient"</span>;

 <span class="hljs-keyword">const</span> fontSans = FontSans({
   <span class="hljs-attr">subsets</span>: [<span class="hljs-string">"latin"</span>],
   <span class="hljs-attr">variable</span>: <span class="hljs-string">"--font-sans"</span>,
 });

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
   <span class="hljs-attr">title</span>: <span class="hljs-string">"MovieMaster"</span>,
   <span class="hljs-attr">description</span>: <span class="hljs-string">"MovieMaster PWA helps you find the latest movies with an easy search by genre, year, and more. It works smoothly on any device, even offline, giving you a great movie browsing experience."</span>,
   <span class="hljs-attr">manifest</span>: <span class="hljs-string">"/web.manifest"</span>,
 };

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{ children }: { children: React.ReactNode }</span>) </span>{
   <span class="hljs-keyword">return</span> (
     <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">suppressHydrationWarning</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">body</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{cn(</span>"<span class="hljs-attr">min-h-screen</span> <span class="hljs-attr">bg-background</span> <span class="hljs-attr">font-sans</span> <span class="hljs-attr">antialiased</span>", <span class="hljs-attr">fontSans.variable</span>)}&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">RootLayoutClient</span>&gt;</span>{children}<span class="hljs-tag">&lt;/<span class="hljs-name">RootLayoutClient</span>&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
     <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></span>
   );
 }
</code></pre>
</li>
<li><p><strong>RootLayoutClient.tsx</strong>: Handles client-side logic, essential for rendering interactive elements and managing UI states."</p>
<pre><code class="lang-javascript"> <span class="hljs-string">"use client"</span>;

 <span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
 <span class="hljs-keyword">import</span> { Toaster } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/ui/sonner"</span>;
 <span class="hljs-keyword">import</span> <span class="hljs-string">"./globals.css"</span>;

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayoutClient</span>(<span class="hljs-params">{ children }: { children: React.ReactNode }</span>) </span>{
   <span class="hljs-keyword">return</span> (
     <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-white flex flex-col"</span>&gt;</span>
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container mx-auto px-4 max-w-[1024px]"</span>&gt;</span>
         {children}
         <span class="hljs-tag">&lt;<span class="hljs-name">Toaster</span> /&gt;</span>
       <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
     <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
   );
 }
</code></pre>
</li>
</ol>
<h4 id="heading-running-and-previewing-the-project"><strong>Running and Previewing the Project</strong></h4>
<p>To start working with your project:</p>
<p><strong>Start the Development Server</strong>: In your terminal, execute:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>This will start the development server, and you can view the application by navigating to http://localhost:3000 in your browser.</p>
<h2 id="heading-how-to-turn-your-web-app-into-a-pwa"><strong>How to Turn Your Web App into a PWA</strong></h2>
<p>To transform your web app into a PWA, there are certain criteria that your app must meet. Let's walk through these requirements and implement the necessary changes step by step.</p>
<h3 id="heading-criteria-for-a-pwa">Criteria for a PWA</h3>
<ol>
<li><p><strong>Served Over HTTPS</strong>: Your app must be served over a secure origin (HTTPS) or <code>localhost</code> for development. If you’re developing locally, this criterion is already met.</p>
</li>
<li><p><strong>Web Manifest File</strong>: A web manifest file provides metadata about your app, such as its name, icons, and start URL. This file is crucial for making your app installable on a user's device.</p>
</li>
<li><p><strong>Service Worker with a</strong> <code>fetch</code> <strong>Event</strong>: Your app must register a service worker with at least a <code>fetch</code> event. Registering a service worker with at least a fetch event is essential for your app to be recognized as a PWA and be installable. Beyond that, service workers enhance your app's performance and reliability, allowing it to cache resources and handle network requests even when offline.</p>
</li>
</ol>
<h3 id="heading-how-to-add-a-web-manifest-file-to-your-nextjs-app"><strong>How to Add a Web Manifest File to Your Next.js App</strong></h3>
<p>To add a web manifest file in your Next.js app, place it in the <strong>public/</strong> directory and reference it in your layout file. Ensure that all the images you include in your manifest file are also in the <strong>public/</strong> directory.</p>
<p>Here’s an example of a <strong>web.manifest</strong> file:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Movie Master"</span>,
  <span class="hljs-attr">"short_name"</span>: <span class="hljs-string">"Moviemaster"</span>,
  <span class="hljs-attr">"theme_color"</span>: <span class="hljs-string">"#8936FF"</span>,
  <span class="hljs-attr">"background_color"</span>: <span class="hljs-string">"#333333"</span>,
  <span class="hljs-attr">"start_url"</span>: <span class="hljs-string">"/"</span>,
  <span class="hljs-attr">"id"</span>: <span class="hljs-string">"MovieMaster"</span>,
  <span class="hljs-attr">"display"</span>: <span class="hljs-string">"standalone"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"MovieMaster PWA helps you find the latest movies with an easy search by genre, year, and more. It works smoothly on any device, even offline, giving you a great movie browsing experience."</span>,
  <span class="hljs-attr">"icons"</span>: [
    {
      <span class="hljs-attr">"purpose"</span>: <span class="hljs-string">"maskable"</span>,
      <span class="hljs-attr">"sizes"</span>: <span class="hljs-string">"512x512"</span>,
      <span class="hljs-attr">"src"</span>: <span class="hljs-string">"icon512_maskable.png"</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"image/png"</span>
    },
    {
      <span class="hljs-attr">"purpose"</span>: <span class="hljs-string">"any"</span>,
      <span class="hljs-attr">"sizes"</span>: <span class="hljs-string">"512x512"</span>,
      <span class="hljs-attr">"src"</span>: <span class="hljs-string">"icon512_rounded.png"</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"image/png"</span>
    }
  ],
  <span class="hljs-attr">"screenshots"</span>: [
    {
      <span class="hljs-attr">"src"</span>: <span class="hljs-string">"screenshot1.png"</span>,
      <span class="hljs-attr">"type"</span>: <span class="hljs-string">"image/png"</span>,
      <span class="hljs-attr">"sizes"</span>: <span class="hljs-string">"1080x1920"</span>,
      <span class="hljs-attr">"form_factor"</span>: <span class="hljs-string">"narrow"</span>
    }
  ]
}
</code></pre>
<h4 id="heading-required-fields"><strong>Required Fields</strong></h4>
<ul>
<li><p><code>name</code>: The full name of your app.</p>
</li>
<li><p><code>short_name</code>: A shorter version of the app’s name, displayed when there isn’t enough space for the full name.</p>
</li>
<li><p><code>icons</code>: Icons representing your app at various sizes.</p>
</li>
<li><p><code>start_url</code>: The URL that opens when the app is launched.</p>
</li>
<li><p><code>display</code>: Defines the display mode (for example, <code>standalone</code> for a full-screen experience).</p>
</li>
</ul>
<h4 id="heading-recommended-fields"><strong>Recommended Fields</strong></h4>
<ul>
<li><code>theme_color</code>: Sets the theme color of the browser’s UI, such as the address bar. This color enhances the native feel of your PWA.</li>
</ul>
<p>This example shows how the theme color (#8936FF) is applied to the browser's UI, giving your PWA a native feel.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726725605476/32366f45-b981-44bc-ac60-0f3661b8ed2c.png" alt="A dark-themed movie search interface displaying &quot;The Avengers&quot; (2012) showing how theme color is applied to the browser's UI" width="2588" height="802" loading="lazy"></p>
<ul>
<li><p><code>background_color</code>: Defines the background color for the splash screen when your app is launched.</p>
</li>
<li><p><code>screenshots</code>: Provide screenshots of your app to improve the installation experience, especially on Android devices.</p>
</li>
</ul>
<p>This example illustrates how screenshots are displayed during the installation process, enhancing the user experience, especially on Android devices.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726725620443/53b6712b-574a-445c-aca2-7c57dd62a268.jpeg" alt="An image showing how screenshots are displayed during the installation process on Android." width="571" height="1280" loading="lazy"></p>
<ul>
<li><code>id</code>: Unique identifier for the app</li>
</ul>
<h3 id="heading-how-to-reference-the-web-manifest-file"><strong>How to Reference the Web Manifest File</strong></h3>
<p>Next, let’s add the manifest file to your pages. In Next.js, you can include it in the <code>metadata</code> of your <strong>Layout.tsx</strong>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> metadata: Metadata = {
  <span class="hljs-attr">title</span>: <span class="hljs-string">"MovieMaster"</span>,
  <span class="hljs-attr">description</span>: <span class="hljs-string">"Find the latest movies with ease."</span>,
  <span class="hljs-attr">manifest</span>: <span class="hljs-string">"/web.manifest"</span>, <span class="hljs-comment">// Link to the manifest file</span>
};
</code></pre>
<h3 id="heading-how-to-register-a-service-worker"><strong>How to Register a Service Worker</strong></h3>
<p>A service worker is a script that your browser runs in the background, allowing you to control how your app handles network requests, caching, and other tasks.</p>
<p>Registering a service worker with at least a <code>fetch</code> event is essential for your app to be recognized as a PWA and be installable.</p>
<p>Create a <strong>service-worker.js</strong> file in the <strong>public/</strong> directory with the following code:</p>
<pre><code class="lang-javascript">self.addEventListener(<span class="hljs-string">'install'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Service Worker installing.'</span>);
});

self.addEventListener(<span class="hljs-string">'activate'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Service Worker activating.'</span>);
});

self.addEventListener(<span class="hljs-string">'fetch'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Fetching:'</span>, event.request.url);
  event.respondWith(fetch(event.request));
});
</code></pre>
<p>Then, register the service worker in your <strong>RootLayoutClient.tsx</strong> file:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayoutClient</span>(<span class="hljs-params">{ children }</span>) </span>{
  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-string">"serviceWorker"</span> <span class="hljs-keyword">in</span> navigator) {
      navigator.serviceWorker
        .register(<span class="hljs-string">"/service-worker.js"</span>)
        .then(<span class="hljs-function">(<span class="hljs-params">registration</span>) =&gt;</span> {
          <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Service Worker registered with scope:"</span>, registration.scope);
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
          <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Service Worker registration failed:"</span>, error);
        });
    }
  }, []);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-white flex flex-col"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container mx-auto px-4 max-w-[1024px]"</span>&gt;</span>
        {children}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Once your app meets all the criteria, users can easily install it on their devices. For example, when using the Edge browser, an install option will appear in the browser’s menu, allowing users to add your app directly to their desktop or home screen.</p>
<p>Here's what the installation process looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726725642915/c7e6af8a-56e8-4eb2-b1b6-fd715ea7210a.png" alt="An image showing the install option on Edge browser" width="1600" height="949" loading="lazy"></p>
<h2 id="heading-how-to-add-offline-support">How to Add Offline Support</h2>
<p>At this stage, even though our app is technically a PWA, it still behaves like a regular web application. Whenever a user requests a resource, the app makes a network request, and if the network fails, the user is greeted with an error page. This isn’t ideal, especially when the power of a PWA lies in its ability to function offline or in poor network conditions.</p>
<p>With a PWA, you can intercept every request made by your app using a service worker. This gives you the flexibility to decide how to serve content—from the network or from a cache. This control allows you to ensure that users can still access the app, even without an internet connection.</p>
<h3 id="heading-how-to-deliver-resources-from-the-network"><strong>How to Deliver Resources from the Network</strong></h3>
<p>Let’s start by looking at how our app currently behaves, which is similar to any standard web application:</p>
<pre><code class="lang-javascript">self.addEventListener(<span class="hljs-string">"fetch"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.respondWith(fetch(event.request));
});
</code></pre>
<p>This code simply fetches resources directly from the network. If the network is unavailable, the request will fail, leading to an error. This is the default behavior for a standard web app.</p>
<h3 id="heading-how-to-implement-offline-support"><strong>How to Implement Offline Support</strong></h3>
<p>To provide an offline experience, we need to cache our app’s resources when the user is online and then serve these cached resources when the user is offline. For this, we’ll use the Cache Storage API, which allows us to store resources locally on the user's device.</p>
<h3 id="heading-what-to-cache"><strong>What to Cache?</strong></h3>
<p>The decision on what to cache depends on the needs of your application. For a movie search app like ours, we’ll want to cache the essential resources required to render a basic version of the application:</p>
<ul>
<li><p>The main HTML page</p>
</li>
<li><p>CSS stylesheets needed to render the site</p>
</li>
<li><p>Images used in the user interface</p>
</li>
<li><p>JavaScript files required for functionality</p>
</li>
<li><p>API request responses</p>
</li>
</ul>
<p><strong>Note:</strong> While you can cache almost anything, be mindful of storage limitations, as all cached items are stored on the user’s device. Use storage wisely to avoid taking up too much space.</p>
<h3 id="heading-when-to-cache"><strong>When to Cache?</strong></h3>
<p>Once we know what to cache, the next thing to consider is when to cache. Should you cache everything during the service worker installation, or should you cache resources as they are requested?</p>
<p>The answer depends on the app's needs, but a good practice is to cache the core files required to render a basic version of the app during the service worker installation.</p>
<p>Here’s how you can do that:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> CACHE_NAME = <span class="hljs-string">"MOVIE_MASTER_V1"</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">cacheCoreAssets</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">await</span> caches.open(CACHE_NAME);
  <span class="hljs-keyword">return</span> cache.addAll([
    <span class="hljs-string">"/"</span>,
    <span class="hljs-string">"/imdb-logo.svg"</span>,
    <span class="hljs-string">"/rotten-tomatoes-logo.svg"</span>,
  ]);
}

self.addEventListener(<span class="hljs-string">"install"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.waitUntil(cacheCoreAssets());
  self.skipWaiting();
});
</code></pre>
<p>In this code, <code>self.skipWaiting()</code> ensures that the new service worker activates immediately after installation, bypassing the waiting phase.</p>
<p>It’s also important to delete old caches when a new service worker is activated:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">clearOldCaches</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> cacheNames = <span class="hljs-keyword">await</span> caches.keys();
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.all(
    cacheNames
      .filter(<span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> name !== CACHE_NAME)
      .map(<span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> caches.delete(name))
  );
}

self.addEventListener(<span class="hljs-string">"activate"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.waitUntil(clearOldCaches());
  self.clients.claim();
});
</code></pre>
<p>The <code>self.clients.claim()</code> method ensures that the new service worker takes control of all pages as soon as it activates.</p>
<h3 id="heading-dynamic-caching"><strong>Dynamic Caching</strong></h3>
<p>Dynamic caching is particularly useful for React apps like ours, where static files are automatically generated. With dynamic caching, you don’t need to know all the files in advance. Instead, it handles the caching process for you as files are requested.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dynamicCaching</span>(<span class="hljs-params">request</span>) </span>{
  <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">await</span> caches.open(CACHE_NAME);

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(request);
    <span class="hljs-keyword">const</span> responseClone = response.clone();
    <span class="hljs-keyword">await</span> cache.put(request, responseClone);
    <span class="hljs-keyword">return</span> response;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Dynamic caching failed:"</span>, error);
    <span class="hljs-keyword">return</span> caches.match(request);
  }
}
</code></pre>
<p>With dynamic caching, files requested by the app are cached as they are fetched, ensuring that they are available for future offline use.</p>
<h3 id="heading-caching-api-requests"><strong>Caching API Requests</strong></h3>
<p>When it comes to caching API responses, instead of caching the entire response, it’s often better to cache the specific data returned by the API. For this, we can use IndexedDB, a local database built into the browser.</p>
<p>IndexedDB is more powerful than the Cache Storage API, especially for storing and retrieving structured data like JSON. This makes it an excellent choice for apps that require storing complex data or handling large amounts of information efficiently.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726726244513/6e99d4b6-fefb-40f1-9ad1-db88c2c7b3da.png" alt="A screenshot showing the structure and data stored in the IndexedDB for the MovieMaster PWA." width="1600" height="1027" loading="lazy"></p>
<h4 id="heading-how-to-set-up-indexeddb"><strong>How to Set Up IndexedDB</strong></h4>
<p>First, create a function to open the database and create an object store:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> DB_NAME = <span class="hljs-string">"MovieMaster"</span>;
<span class="hljs-keyword">const</span> DB_VERSION = <span class="hljs-number">1</span>;
<span class="hljs-keyword">const</span> DB_STORE_NAME = <span class="hljs-string">"myStore"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">openDb</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> request = indexedDB.open(DB_NAME, DB_VERSION);
    request.onsuccess = <span class="hljs-function">() =&gt;</span> resolve(request.result);
    request.onerror = <span class="hljs-function">() =&gt;</span> reject(request.error);
    request.onupgradeneeded = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> db = event.target.result;
      db.createObjectStore(DB_STORE_NAME, { <span class="hljs-attr">keyPath</span>: <span class="hljs-string">"url"</span> });
    };
  });
}
</code></pre>
<p>Next, create functions to add data to and retrieve data from the database:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addData</span>(<span class="hljs-params">url, jsonData</span>) </span>{
  <span class="hljs-keyword">const</span> db = <span class="hljs-keyword">await</span> openDb();
  <span class="hljs-keyword">const</span> transaction = db.transaction(DB_STORE_NAME, <span class="hljs-string">"readwrite"</span>);
  <span class="hljs-keyword">const</span> store = transaction.objectStore(DB_STORE_NAME);

  <span class="hljs-keyword">const</span> data = {
    url,
    <span class="hljs-attr">response</span>: <span class="hljs-built_in">JSON</span>.stringify(jsonData),
  };

  <span class="hljs-keyword">const</span> request = store.put(data);
  <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    request.onsuccess = <span class="hljs-function">() =&gt;</span> resolve();
    request.onerror = <span class="hljs-function">() =&gt;</span> reject(request.error);
  });
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params">url</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> db = <span class="hljs-keyword">await</span> openDb();
    <span class="hljs-keyword">const</span> transaction = db.transaction(DB_STORE_NAME, <span class="hljs-string">"readonly"</span>);
    <span class="hljs-keyword">const</span> store = transaction.objectStore(DB_STORE_NAME);

    <span class="hljs-keyword">const</span> request = store.get(url);

    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
      request.onsuccess = <span class="hljs-function">() =&gt;</span> resolve(request.result);
      request.onerror = <span class="hljs-function">() =&gt;</span> reject(request.error);
    });

    <span class="hljs-keyword">if</span> (result &amp;&amp; result.response) {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">JSON</span>.parse(result.response);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error retrieving from IndexedDB:"</span>, error);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
  }
}
</code></pre>
<h3 id="heading-how-to-serve-cached-resources"><strong>How to Serve Cached Resources</strong></h3>
<p>Once we have cached our assets and stored API data in IndexedDB, the next step is to serve this data to users when they are offline. There are several strategies to achieve this:</p>
<h4 id="heading-cache-first-strategy"><strong>Cache First Strategy</strong></h4>
<p>In the cache-first strategy, we check if a resource is available in the cache. If it is, we serve it from the cache; if not, we fetch it from the network. This is particularly useful for serving static assets like HTML, CSS, and JavaScript files:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">cacheFirstStrategy</span>(<span class="hljs-params">request</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">await</span> caches.open(CACHE_NAME);
    <span class="hljs-keyword">const</span> cachedResponse = <span class="hljs-keyword">await</span> cache.match(request);

    <span class="hljs-keyword">if</span> (cachedResponse) {
      <span class="hljs-keyword">return</span> cachedResponse;
    }

    <span class="hljs-keyword">const</span> networkResponse = <span class="hljs-keyword">await</span> fetch(request);
    <span class="hljs-keyword">const</span> responseClone = networkResponse.clone();
    <span class="hljs-keyword">await</span> cache.put(request, responseClone);
    <span class="hljs-keyword">return</span> networkResponse;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Cache first strategy failed:"</span>, error);
    <span class="hljs-keyword">return</span> caches.match(<span class="hljs-string">"/offline"</span>);
  }
}

self.addEventListener(<span class="hljs-string">"fetch"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { request } = event;
  <span class="hljs-keyword">if</span> (event.request.mode === <span class="hljs-string">"navigate"</span>) {
    event.respondWith(cacheFirstStrategy(request));
  } <span class="hljs-keyword">else</span> {
    event.respondWith(dynamicCaching(request));
  }
});
</code></pre>
<p>In this setup, the cache-first strategy is applied when navigating to new pages, while dynamic caching handles other requests.</p>
<h4 id="heading-network-first-strategy"><strong>Network First Strategy</strong></h4>
<p>The network-first strategy is the opposite: it attempts to fetch resources from the network first, and if the network is unavailable, it falls back to the cache. This strategy is particularly useful for API requests where you want the most up-to-date data:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">networkFirstStrategy</span>(<span class="hljs-params">request</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> networkResponse = <span class="hljs-keyword">await</span> fetch(request);

    <span class="hljs-keyword">if</span> (networkResponse.ok) {
      <span class="hljs-keyword">const</span> responseClone = networkResponse.clone();
      <span class="hljs-keyword">const</span> responseData = <span class="hljs-keyword">await</span> responseClone.json();
      <span class="hljs-keyword">await</span> addData(request.url, responseData);
      <span class="hljs-keyword">return</span> networkResponse;
    }

    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Network response was not ok"</span>);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Network first strategy failed:"</span>, error);
    <span class="hljs-keyword">const</span> cachedResponse = <span class="hljs-keyword">await</span> getData(request.url);

    <span class="hljs-keyword">if</span> (cachedResponse) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Using cached response:"</span>, cachedResponse);
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-built_in">JSON</span>.stringify(cachedResponse), {
        <span class="hljs-attr">status</span>: <span class="hljs-number">200</span>,
        <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> },
      });
    }

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-string">"[]"</span>, { <span class="hljs-attr">status</span>: <span class="hljs-number">200</span> });
  }
}

self.addEventListener(<span class="hljs-string">"fetch"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { request } = event;
  <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">new</span> URL(request.url);

  <span class="hljs-keyword">if</span> (url.origin === <span class="hljs-string">"https://www.omdbapi.com"</span>) {
    event.respondWith(networkFirstStrategy(request));
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (event.request.mode === <span class="hljs-string">"navigate"</span>) {
    event.respondWith(cacheFirstStrategy(request));
  } <span class="hljs-keyword">else</span> {
    event.respondWith(dynamicCaching(request));
  }
});
</code></pre>
<p>In our app, we use the network-first strategy for API calls, ensuring that the user gets the latest data when online, while falling back to cached data in IndexedDB when offline.</p>
<h4 id="heading-full-service-worker-code"><strong>Full Service Worker Code</strong></h4>
<p>Here’s the complete <strong>service-worker.js</strong> file that incorporates everything we’ve discussed:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> CACHE_NAME = <span class="hljs-string">"MOVIE_MASTER_V1"</span>;
<span class="hljs-keyword">const</span> DB_NAME = <span class="hljs-string">"MovieMaster"</span>;
<span class="hljs-keyword">const</span> DB_VERSION = <span class="hljs-number">1</span>;
<span class="hljs-keyword">const</span> DB_STORE_NAME = <span class="hljs-string">"myStore"</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">cacheCoreAssets</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">await</span> caches.open(CACHE_NAME);
  <span class="hljs-keyword">return</span> cache.addAll([
    <span class="hljs-string">"/"</span>,
    <span class="hljs-string">"/imdb-logo.svg"</span>,
    <span class="hljs-string">"/rotten-tomatoes-logo.svg"</span>,
    <span class="hljs-string">"/offline"</span>,
  ]);
}

self.addEventListener(<span class="hljs-string">"install"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.waitUntil(cacheCoreAssets());
  self.skipWaiting();
});

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">clearOldCaches</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> cacheNames = <span class="hljs-keyword">await</span> caches.keys();
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.all(
    cacheNames
      .filter(<span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> name !== CACHE_NAME)
      .map(<span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> caches.delete(name))
  );
}

self.addEventListener(<span class="hljs-string">"activate"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.waitUntil(clearOldCaches());
  self.clients.claim();
});

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">dynamicCaching</span>(<span class="hljs-params">request</span>) </span>{
  <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">await</span> caches.open(CACHE_NAME);

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(request);
    <span class="hljs-keyword">const</span> responseClone = response.clone();
    <span class="hljs-keyword">await</span> cache.put(request, responseClone);
    <span class="hljs-keyword">return</span> response;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Dynamic caching failed:"</span>, error);
    <span class="hljs-keyword">return</span> caches.match(request);
  }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">openDb</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> request = indexedDB.open(DB_NAME, DB_VERSION);
    request.onsuccess = <span class="hljs-function">() =&gt;</span> resolve(request.result);
    request.onerror = <span class="hljs-function">() =&gt;</span> reject(request.error);
    request.onupgradeneeded = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
      <span class="hljs-keyword">const</span> db = event.target.result;
      db.createObjectStore(DB_STORE_NAME, { <span class="hljs-attr">keyPath</span>: <span class="hljs-string">"url"</span> });
    };
  });
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addData</span>(<span class="hljs-params">url, jsonData</span>) </span>{
  <span class="hljs-keyword">const</span> db = <span class="hljs-keyword">await</span> openDb();
  <span class="hljs-keyword">const</span> transaction = db.transaction(DB_STORE_NAME, <span class="hljs-string">"readwrite"</span>);
  <span class="hljs-keyword">const</span> store = transaction.objectStore(DB_STORE_NAME);

  <span class="hljs-keyword">const</span> data = {
    url,
    <span class="hljs-attr">response</span>: <span class="hljs-built_in">JSON</span>.stringify(jsonData),
  };

  <span class="hljs-keyword">const</span> request = store.put(data);
  <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
    request.onsuccess = <span class="hljs-function">() =&gt;</span> resolve();
    request.onerror = <span class="hljs-function">() =&gt;</span> reject(request.error);
  });
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params">url</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> db = <span class="hljs-keyword">await</span> openDb();
    <span class="hljs-keyword">const</span> transaction = db.transaction(DB_STORE_NAME, <span class="hljs-string">"readonly"</span>);
    <span class="hljs-keyword">const</span> store = transaction.objectStore(DB_STORE_NAME);

    <span class="hljs-keyword">const</span> request = store.get(url);

    <span class="hljs-keyword">const</span> result = <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
      request.onsuccess = <span class="hljs-function">() =&gt;</span> resolve(request.result);
      request.onerror = <span class="hljs-function">() =&gt;</span> reject(request.error);
    });

    <span class="hljs-keyword">if</span> (result &amp;&amp; result.response) {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">JSON</span>.parse(result.response);
    }

    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error retrieving from IndexedDB:"</span>, error);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;
  }
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">cacheFirstStrategy</span>(<span class="hljs-params">request</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">await</span> caches.open(CACHE_NAME);
    <span class="hljs-keyword">const</span> cachedResponse = <span class="hljs-keyword">await</span> cache.match(request);

    <span class="hljs-keyword">if</span> (cachedResponse) {
      <span class="hljs-keyword">return</span> cachedResponse;
    }

    <span class="hljs-keyword">const</span> networkResponse = <span class="hljs-keyword">await</span> fetch(request);
    <span class="hljs-keyword">const</span> responseClone = networkResponse.clone();
    <span class="hljs-keyword">await</span> cache.put(request, responseClone);
    <span class="hljs-keyword">return</span> networkResponse;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Cache first strategy failed:"</span>, error);
    <span class="hljs-keyword">return</span> caches.match(<span class="hljs-string">"/offline"</span>);
  }
}

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">networkFirstStrategy</span>(<span class="hljs-params">request</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> networkResponse = <span class="hljs-keyword">await</span> fetch(request);

    <span class="hljs-keyword">if</span> (networkResponse.ok) {
      <span class="hljs-keyword">const</span> responseClone = networkResponse.clone();
      <span class="hljs-keyword">const</span> responseData = <span class="hljs-keyword">await</span> responseClone.json();
      <span class="hljs-keyword">await</span> addData(request.url, responseData);
      <span class="hljs-keyword">return</span> networkResponse;
    }

    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Network response was not ok"</span>);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Network first strategy failed:"</span>, error);
    <span class="hljs-keyword">const</span> cachedResponse = <span class="hljs-keyword">await</span> getData(request.url);

    <span class="hljs-keyword">if</span> (cachedResponse) {
      <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Using cached response:"</span>, cachedResponse);
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-built_in">JSON</span>.stringify(cachedResponse), {
        <span class="hljs-attr">status</span>: <span class="hljs-number">200</span>,
        <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> },
      });
    }

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(<span class="hljs-string">"[]"</span>, { <span class="hljs-attr">status</span>: <span class="hljs-number">200</span> });
  }
}

self.addEventListener(<span class="hljs-string">"fetch"</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> { request } = event;
  <span class="hljs-keyword">const</span> url = <span class="hljs-keyword">new</span> URL(request.url);

  <span class="hljs-keyword">if</span> (url.origin === <span class="hljs-string">"https://www.omdbapi.com"</span>) {
    event.respondWith(networkFirstStrategy(request));
  } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (event.request.mode === <span class="hljs-string">"navigate"</span>) {
    event.respondWith(cacheFirstStrategy(request));
  } <span class="hljs-keyword">else</span> {
    event.respondWith(dynamicCaching(request));
  }
});
</code></pre>
<p>With this setup, your PWA is now fully equipped to handle both static and dynamic content, provide an offline experience, and cache API data intelligently.</p>
<h4 id="heading-further-reading"><strong>Further Reading</strong></h4>
<p>There are many more strategies and nuances to building a robust offline experience with service workers. If you want to dive deeper into this topic, consider reading more about:</p>
<ul>
<li><p>Different caching strategies: Cache-First, Network-First, Stale-While-Revalidate, and so on.</p>
</li>
<li><p>Advanced service worker features like background sync and push notifications.</p>
</li>
<li><p>Best practices for managing cache and storage limits</p>
</li>
</ul>
<p>By understanding and implementing these concepts, you can ensure that your app remains functional and user-friendly, even in challenging network conditions.</p>
<h3 id="heading-providing-a-fallback-page"><strong>Providing a Fallback Page</strong></h3>
<p>Even with caching strategies in place, there may be times when users try to access a resource that isn’t available offline and in the network. To handle these situations gracefully, we can create a fallback page. This page will be shown whenever a user tries to access content that can't be retrieved from either the cache or the network.</p>
<p>If you cloned the example project for this tutorial, you should already have a fallback page located in the app directory. This page is designed to handle offline scenarios gracefully and includes a simple Tic-Tac-Toe game for users to play while waiting for the connection to be restored. Here’s what the fallback page looks like:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"use client"</span>;
<span class="hljs-keyword">import</span> TicTacToe <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TicTacToe"</span>;
<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/navigation"</span>;
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;

<span class="hljs-keyword">const</span> Fallback: React.FC = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [isOnline, setIsOnline] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> router = useRouter();

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> handleOnline = <span class="hljs-function">() =&gt;</span> {
      setIsOnline(<span class="hljs-literal">true</span>);
      <span class="hljs-comment">// Redirect to homepage if online</span>
      router.push(<span class="hljs-string">"/"</span>);
    };

    <span class="hljs-keyword">const</span> handleOffline = <span class="hljs-function">() =&gt;</span> {
      setIsOnline(<span class="hljs-literal">false</span>);
    };

    <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"online"</span>, handleOnline);
    <span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"offline"</span>, handleOffline);

    <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> {
      <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">"online"</span>, handleOnline);
      <span class="hljs-built_in">window</span>.removeEventListener(<span class="hljs-string">"offline"</span>, handleOffline);
    };
  }, [router]);

  <span class="hljs-keyword">const</span> handleRefresh = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (navigator.onLine) {
      router.push(<span class="hljs-string">"/"</span>);
    } <span class="hljs-keyword">else</span> {
      setIsOnline(<span class="hljs-literal">false</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex mx-auto h-screen max-w-[500px] w-full flex-col items-center justify-center h-screen bg-foreground text-black p-6 mt-12 text-white"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl font-bold mb-6"</span>&gt;</span>
        {isOnline ? "You are online!" : "You are offline"}
      <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg text-center mb-6"</span>&gt;</span>
        {isOnline
          ? "You are back online."
          : "Please check your internet connection and try again."}
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">""</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">TicTacToe</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      {isOnline ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
          <span class="hljs-attr">href</span>=<span class="hljs-string">{</span>"/"}
          <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-6 px-4 py-2 bg-blue-500 text-white rounded shadow hover:bg-blue-600"</span>
        &gt;</span>
          Return to Homepage
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleRefresh}</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-6 px-4 py-2 bg-blue-500 text-white rounded shadow hover:bg-blue-600"</span>
        &gt;</span>
          Refresh
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Fallback;
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726726501345/46e5c3a7-7640-4e54-b6b8-2f43c5b24dcd.png" alt="An image showing our Fallback page" width="1600" height="1195" loading="lazy"></p>
<p><strong>Note:</strong> You can customize this fallback page to suit your application’s needs, whether that’s displaying helpful offline content, providing a message, or offering a small interactive feature like the Tic-Tac-Toe game included here.</p>
<h4 id="heading-caching-the-fallback-page"><strong>Caching the Fallback Page</strong></h4>
<p>Next, ensure that the fallback page is cached when the service worker is installed:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> CACHE_NAME = <span class="hljs-string">"MOVIE_MASTER_V1"</span>;

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">cacheCoreAssets</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">await</span> caches.open(CACHE_NAME);
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> cache.addAll([
    <span class="hljs-string">"/"</span>,
    <span class="hljs-string">"/fallback"</span>,
    <span class="hljs-comment">// other assets</span>
  ]);
}
</code></pre>
<h4 id="heading-serving-the-fallback-page"><strong>Serving the Fallback Page</strong></h4>
<p>Finally, modify the <code>cacheFirstStrategy</code> to serve the <strong>offline.html</strong> page when a request fails:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">cacheFirstStrategy</span>(<span class="hljs-params">request</span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> cache = <span class="hljs-keyword">await</span> caches.open(CACHE_NAME);
    <span class="hljs-keyword">const</span> cachedResponse = <span class="hljs-keyword">await</span> cache.match(request);

    <span class="hljs-keyword">if</span> (cachedResponse) {
      <span class="hljs-keyword">return</span> cachedResponse;
    }

    <span class="hljs-keyword">const</span> networkResponse = <span class="hljs-keyword">await</span> fetch(request);
    <span class="hljs-keyword">const</span> responseClone = networkResponse.clone();
    <span class="hljs-keyword">await</span> cache.put(request, responseClone);
    <span class="hljs-keyword">return</span> networkResponse;
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Cache first strategy failed:"</span>, error);
    <span class="hljs-keyword">return</span> caches.match(<span class="hljs-string">"/offline.html"</span>);
  }
}
</code></pre>
<p>This approach ensures that users always see a meaningful message instead of an error when they’re offline or when a resource is unavailable.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>With our Next.js app set up, we’ve successfully transformed it into a fully functional Progressive Web App (PWA), making it better and more user-friendly.</p>
<p>This guide showed how to build a strong PWA using Next.js by adding features like offline support, caching, and service workers. These improvements boost performance and provide a smooth experience on all devices, combining the best of web and native apps.</p>
<p>With these tips, you’ll be ready to create engaging, reliable, and high-performance PWAs that stand out in web development.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Host Your Project on GitHub – Explained With Examples ]]>
                </title>
                <description>
                    <![CDATA[ Seven years ago, I began my journey into web development with HTML and CSS. As soon as I got the hang of JavaScript, I built my first website. The excitement was overwhelming, and I wanted to share it with my friends and the world. Like many beginner... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/host-your-first-project-on-github/</link>
                <guid isPermaLink="false">66d46156182810487e0ce1be</guid>
                
                    <category>
                        <![CDATA[ deployment ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Hosting ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Thu, 08 Aug 2024 11:37:16 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/08/Screenshot-2024-08-04-at-11.47.51-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Seven years ago, I began my journey into web development with HTML and CSS. As soon as I got the hang of JavaScript, I built my first website. The excitement was overwhelming, and I wanted to share it with my friends and the world.</p>
<p>Like many beginners, I started researching hosting platforms, only to find out about the cost of domains and hosting. That's when I discovered Git and GitHub, realizing I could share my projects without spending a dime.</p>
<p>If you're in the same boat, unsure about Git and GitHub and how to share your projects, this article is for you. It's the guide I wish I had seven years ago.</p>
<p>To demonstrate the power of Git and GitHub, we'll be using a real-world project as an example. Let's take the "IP Address Tracker application" project from <a target="_blank" href="https://www.freecodecamp.org/news/learn-rest-apis-javascript-project/#practical-example-how-to-build-a-web-application-with-a-public-rest-api">this freeCodeCamp tutorial</a>. You can download the source code for the project <a target="_blank" href="https://github.com/iamspruce/ip-address-tracker/">here</a>.</p>
<p>If you've followed the tutorial and built the project, or if you have a project you'd like to share, this article is for you. We'll walk you through the steps to host your project on GitHub, making it accessible to the world.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-audience">Audience</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-prerequisite-knowledge">Prerequisite Knowledge</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-getting-started-with-git-and-github">Getting Started With Git and GitHub</a></p>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-git">What is Git?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-github">What is GitHub?</a></p>
</li>
</ol>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-git-and-github">How to Set Up Git and GitHub</a></p>
<ol>
<li><p><a class="post-section-overview" href="#heading-how-to-install-git-on-windows">How to Install Git on Windows</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-install-git-on-macos">How to Install Git on macOS</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-install-git-on-linux">How to Install Git on Linux</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-github-account">How to Create a GitHub Account</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-configure-git">How to Configure Git</a></p>
</li>
</ol>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-initialize-a-git-repository">How to Initialize a Git Repository</a></p>
<ol>
<li><p><a class="post-section-overview" href="#heading-step-1-download-and-open-your-project">Step 1: Download and Open Your Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-open-the-project-in-vs-code">Step 2: Open the Project in VS Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-open-the-terminal-in-vs-code">Step 3: Open the Terminal in VS Code</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-initialize-a-git-repository">Step 4: Initialize a Git Repository</a></p>
</li>
</ol>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-track-changes-with-git">How to Track Changes with Git</a></p>
<ol>
<li><p><a class="post-section-overview" href="#heading-preparing-changes-with-git-add">Preparing Changes with git add</a></p>
<ol>
<li><p><a class="post-section-overview" href="#heading-adding-individual-files">Adding Individual Files</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-adding-all-changes-at-once">Adding All Changes at Once</a></p>
</li>
</ol>
</li>
<li><p><a class="post-section-overview" href="#heading-saving-changes-with-git-commit">Saving Changes with git commit</a></p>
</li>
</ol>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-push-your-project-to-github">How to Push Your Project to GitHub</a></p>
<ol>
<li><p><a class="post-section-overview" href="#heading-step-1-create-a-new-repository-on-github">Step 1: Create a New Repository on GitHub</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-link-your-local-repository-to-github">Step 2: Link Your Local Repository to GitHub</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-push-your-local-changes-to-github">Step 3: Push Your Local Changes to GitHub</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-verify-your-repository-on-github">Step 4: Verify Your Repository on GitHub</a></p>
</li>
</ol>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-host-your-project-on-github-pages">How to Host Your Project on GitHub Pages</a></p>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-are-github-pages">What are GitHub Pages?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-enable-github-pages">How to Enable GitHub Pages</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-get-your-github-pages-url">How to Get Your GitHub Pages URL</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-update-your-github-pages-site">How to Update Your GitHub Pages Site</a></p>
</li>
</ol>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-audience">Audience</h2>
<p>This guide is for beginner developers who have started learning HTML, CSS, and JavaScript and want to learn how to share their projects using Git and GitHub.</p>
<h2 id="heading-prerequisite-knowledge">Prerequisite Knowledge</h2>
<p>Before diving in, ensure you are familiar with:</p>
<ul>
<li><p>Basic command-line operations.</p>
</li>
<li><p>HTML, CSS, and JavaScript fundamentals.</p>
</li>
<li><p>A text editor like VS Code.</p>
</li>
</ul>
<h2 id="heading-getting-started-with-git-and-github">Getting Started With Git and GitHub</h2>
<p>I am not going to try to bore you with the differences between Git and GitHub. I am sure there are tons of resources in the world wide web already covering that but from a beginner's point of view, here is what they are:</p>
<h3 id="heading-what-is-git">What is Git?</h3>
<p>Git is a tool that helps you keep track of all the changes you make in your project's code. Imagine building a website about cats. If you change the website's title from "Cat Facts" to "All About Cats," Git will remember the change. If you later decide that you prefer "Cat Facts," Git lets you go back to that version easily.</p>
<p>It's like having a record of every edit, addition, and deletion you make to your project, so you can always revisit previous versions and make changes with confidence.</p>
<h3 id="heading-what-is-github">What is GitHub?</h3>
<p>GitHub is like a cloud-based scrapbook for your code. It's an online record where you save every edit, addition, and deletion you make to your project, so you can access it from anywhere and share it with others.</p>
<p>Imagine having a digital filing cabinet where you can store and manage different versions of your website. You can invite friends to see and even help you with your project, making it easy to collaborate. GitHub tracks changes and keeps everything organized, so if something goes wrong, you can always go back to a previous version.</p>
<h2 id="heading-how-to-set-up-git-and-github">How to Set Up Git and GitHub</h2>
<p>Now that we know what Git and GitHub are, let's get them set up on your computer. Follow these step-by-step instructions:</p>
<h3 id="heading-how-to-install-git-on-windows">How to Install Git on Windows</h3>
<p>You can download the Git installer <a target="_blank" href="https://git-scm.com/">here</a>.</p>
<p>Run the installer and follow the setup instructions, keeping the default settings.</p>
<h3 id="heading-how-to-install-git-on-macos">How to Install Git on macOS</h3>
<p>Open the Terminal on your Mac. You can find it in Applications &gt; Utilities or use Spotlight to search for it.</p>
<p>Install Git using Homebrew by copying and pasting the following commands:</p>
<pre><code class="lang-bash">/bin/bash -c <span class="hljs-string">"<span class="hljs-subst">$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)</span>"</span>
brew install git
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">==&gt; Downloading https://github.com/Homebrew/brew/tarballs/...
==&gt; Installing git
==&gt; Pouring git-2.43.0.mojave.bottle.tar.gz
🍺  /usr/<span class="hljs-built_in">local</span>/Cellar/git/2.30.1: 1,434 files, 43.8MB
</code></pre>
<h3 id="heading-how-to-install-git-on-linux">How to Install Git on Linux</h3>
<p>Open Terminal on your Linux machine. Then use your distribution's package manager to install Git.</p>
<p>For example, on Ubuntu, copy and paste the following commands:</p>
<pre><code class="lang-bash">sudo apt-get update
sudo apt-get install git
</code></pre>
<p>Output:</p>
<pre><code class="lang-plaintext">Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
git-man liberror-perl
Suggested packages:
git-daemon-run git-daemon-sysvinit git-doc git-el git-email git-gui gitk
gitweb git-mediawiki git-arch git-cvs git-svn git-hg
The following NEW packages will be installed:
git git-man liberror-perl
0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
Need to get 7,841 kB of archives.
After this operation, 43.8 MB of additional disk space will be used.
</code></pre>
<p>To verify the installation, open Terminal (if it's not already open) and type the following command to verify the installation:</p>
<pre><code class="lang-bash">git --version
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">git version 2.43.0
</code></pre>
<p>You should see the installed Git version displayed.</p>
<h3 id="heading-how-to-create-a-github-account">How to Create a GitHub Account</h3>
<ul>
<li><p>Go to <a target="_blank" href="https://github.com/">GitHub</a> and click on "Sign up."</p>
</li>
<li><p>Follow the instructions to create your account, choose a username and password, and verify your email.</p>
</li>
<li><p>Once your account is set up, customize your profile with a bio, profile picture, and links to your personal website or social media.</p>
</li>
</ul>
<h3 id="heading-how-to-configure-git">How to Configure Git</h3>
<p>Open Terminal and configure Git with the same username and email as your GitHub account:</p>
<pre><code class="lang-bash">git config --global user.name <span class="hljs-string">"Your GitHub Username"</span>
git config --global user.email <span class="hljs-string">"your.email@example.com"</span>
</code></pre>
<p>No output will be displayed, but Git will store your credentials for future use.</p>
<h2 id="heading-how-to-initialize-a-git-repository">How to Initialize a Git Repository</h2>
<p>Now that you have Git and GitHub set up, let's start by initializing Git in a project. You can use any project of your choice or follow along with our example using the "IP Address Tracker" project.</p>
<h3 id="heading-step-1-download-and-open-your-project">Step 1: Download and Open Your Project</h3>
<p>Download the source code for your chosen project or use the "IP Address Tracker" project from <a target="_blank" href="https://github.com/iamspruce/ip-address-tracker/">this link</a>. Extract the downloaded ZIP file to a location on your computer. This will provide a concrete example to demonstrate Git concepts.</p>
<h3 id="heading-step-2-open-the-project-in-vs-code">Step 2: Open the Project in VS Code</h3>
<p>Open Visual Studio Code and click on "File" &gt; "Open Folder" to select the folder where you extracted the project.</p>
<h3 id="heading-step-3-open-the-terminal-in-vs-code">Step 3: Open the Terminal in VS Code</h3>
<p>Click on "Terminal" &gt; "New Terminal" to open the terminal in VS Code, where we'll interact with Git using commands.</p>
<h3 id="heading-step-4-initialize-a-git-repository">Step 4: Initialize a Git Repository</h3>
<p>Initialize a Git repository by running the following command:</p>
<pre><code class="lang-bash">git init
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Initialized empty Git repository <span class="hljs-keyword">in</span> /Users/spruceemmanuel/Documents/IP Address Tracker/.git/
</code></pre>
<p>This command creates a new hidden folder called <strong>.git</strong> in your project folder, which tracks changes to our project files. When you run <code>git init</code>, Git sets up the necessary files and directories to start versioning our project. This includes:</p>
<ul>
<li><p>A <strong>.git</strong> folder that stores all the metadata for your repository</p>
</li>
<li><p>A main branch, which is the default branch for your repository</p>
</li>
<li><p>A HEAD pointer, which points to the current branch (in this case, main).</p>
</li>
</ul>
<p>By initializing a Git repository, you're telling Git to start tracking changes to your project files. This allows you to version your code, collaborate with others, and maintain a record of changes.</p>
<h2 id="heading-how-to-track-changes-with-git">How to Track Changes with Git</h2>
<p>Now that we’ve set up Git, it’s ready to keep track of changes in our project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/Screenshot-2024-08-04-at-11.30.49-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>VSCode source control</em></p>
<p>Git notices change in our files, but before we can save these changes, we need to tell Git to do so.</p>
<h3 id="heading-preparing-changes-with-git-add">Preparing Changes with git add</h3>
<p>To get our changes ready to save, we use the <code>git add</code> command. Here’s how it works:</p>
<h4 id="heading-adding-individual-files">Adding Individual Files</h4>
<p>If you want to add specific files, like index.html, script.js, or styles.css, you can use git add followed by the file name. For example:</p>
<pre><code class="lang-bash">git add index.html
</code></pre>
<h4 id="heading-adding-all-changes-at-once">Adding All Changes at Once</h4>
<p>If you want to add all modified files in the project to the staging area, use:</p>
<pre><code class="lang-bash">git add .
</code></pre>
<h3 id="heading-saving-changes-with-git-commit">Saving Changes with git commit</h3>
<p>Once we’ve used git add, we use git commit to save our changes. Here’s how to do it:</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"Describe your changes here"</span>
</code></pre>
<p>Replace "Describe your changes here" with a brief description of what you’ve changed. For example:</p>
<pre><code class="lang-bash">git commit -m <span class="hljs-string">"Update index.html with new content"</span>
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">[master (root-commit) be9b1cd] Update index.html with new content
3 files changed, 386 insertions(+)
create mode 100644 index.html
create mode 100644 script.js
create mode 100644 styles.css
</code></pre>
<p>By using <code>git add</code> and <code>git commit</code>, you’re instructing Git to track and save specific versions of your project. This helps you manage changes, collaborate with others, and maintain a record of your progress.</p>
<h2 id="heading-how-to-push-your-project-to-github">How to Push Your Project to GitHub</h2>
<p>Now that we have our changes tracked and committed locally, it’s time to upload our project to GitHub so we can share it with the world.</p>
<h3 id="heading-step-1-create-a-new-repository-on-github">Step 1: Create a New Repository on GitHub</h3>
<ul>
<li><p>Go to GitHub and log in to your account.</p>
</li>
<li><p>Click the "+" icon in the upper-right corner and select "New repository."</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/Screenshot-2024-08-04-at-11.36.23-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ul>
<li><p>Fill out the repository name (for example: "ip-address-tracker"), and add a description if you like.</p>
</li>
<li><p>Choose whether you want the repository to be public or private.</p>
</li>
<li><p>Do not initialize the repository with a <strong>README</strong>, <strong>gitignore</strong>, or license (since we already have a local repository set up).</p>
</li>
<li><p>Click "Create repository."</p>
</li>
</ul>
<h3 id="heading-step-2-link-your-local-repository-to-github">Step 2: Link Your Local Repository to GitHub</h3>
<p>To connect your local repository with the new GitHub repository, you need to add a remote origin. Follow these steps:</p>
<ul>
<li><p>Copy the URL of your new GitHub repository. It should look something like this: https://github.com/yourusername/ip-address-tracker.git</p>
</li>
<li><p>Open Terminal in Visual Studio Code and run the following command:</p>
</li>
</ul>
<pre><code class="lang-bash">git branch -M main
git remote add origin https://github.com/yourusername/ip-address-tracker.git
</code></pre>
<h3 id="heading-step-3-push-your-local-changes-to-github">Step 3: Push Your Local Changes to GitHub</h3>
<p>Now, push your local commits to the GitHub repository with:</p>
<pre><code class="lang-bash">git push -u origin main
</code></pre>
<p>Output:</p>
<pre><code class="lang-bash">Enumerating objects: 8, <span class="hljs-keyword">done</span>.
Counting objects: 100% (8/8), <span class="hljs-keyword">done</span>.
Compressing objects: 100% (4/4), <span class="hljs-keyword">done</span>.
Writing objects: 100% (6/6), 645 bytes | 645.00 KiB/s, <span class="hljs-keyword">done</span>.
Total 6 (delta 2), reused 0 (delta 0)
To https://github.com/yourusername/ip-address-tracker.git
* [new branch]      main -&gt; main
Branch <span class="hljs-string">'main'</span> <span class="hljs-built_in">set</span> up to track remote branch <span class="hljs-string">'main'</span> from <span class="hljs-string">'origin'</span>.
</code></pre>
<h3 id="heading-step-4-verify-your-repository-on-github">Step 4: Verify Your Repository on GitHub</h3>
<p>Go back to your GitHub repository page. You should see all your files and commit history available online.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/Screenshot-2024-08-04-at-8.55.48-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>A Hosted Repository on GitHub</em></p>
<h2 id="heading-how-to-host-your-project-on-github-pages">How to Host Your Project on GitHub Pages</h2>
<p>Now that your project has been initialized with Git and pushed to GitHub, let’s host it on GitHub Pages. GitHub Pages is a free service that allows you to publish web projects directly from a GitHub repository.</p>
<h3 id="heading-what-are-github-pages">What are GitHub Pages?</h3>
<p>GitHub Pages turns your GitHub repository into a website. It's an easy way to showcase your projects without needing a separate hosting service. You can create static websites directly from your repositories.</p>
<h3 id="heading-how-to-enable-github-pages">How to Enable GitHub Pages</h3>
<ul>
<li><p>Go to your GitHub repository in a web browser.</p>
</li>
<li><p>Click on the "Settings" tab.</p>
</li>
<li><p>Scroll down to the "Pages" section in the left-hand menu.</p>
</li>
<li><p>Under "Source," select the branch you want to publish from (typically main or master), and choose the root folder.</p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/Screenshot-2024-08-04-at-11.12.19-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Selecting the branch and root folder for GitHub Pages.</em></p>
<ul>
<li>Click "Save."</li>
</ul>
<h3 id="heading-how-to-get-your-github-pages-url">How to Get Your GitHub Pages URL</h3>
<p>After enabling GitHub Pages, GitHub will provide you with a URL where your site is published. It usually follows this format:</p>
<pre><code class="lang-bash">https://&lt;username&gt;.github.io/&lt;repository-name&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/Screenshot-2024-08-04-at-11.19.05-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>The URL where your GitHub Pages site is published.</em></p>
<p>Open your browser and paste the URL to see your live website.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/08/Screenshot-2024-08-04-at-10.56.40-PM-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Viewing the live website on GitHub Pages.</em></p>
<h3 id="heading-how-to-update-your-github-pages-site">How to Update Your GitHub Pages Site</h3>
<p>Every time you push changes to the selected branch in your repository, GitHub Pages will automatically update your live site. Here’s a quick reminder on how to push changes:</p>
<ul>
<li><p>Make changes to your project files.</p>
</li>
<li><p>Add and commit your changes:</p>
</li>
</ul>
<pre><code class="lang-bash">git add .
git commit -m <span class="hljs-string">"Your commit message"</span>
</code></pre>
<ul>
<li>Push the changes to GitHub:</li>
</ul>
<pre><code class="lang-bash">git push origin main
</code></pre>
<p>With these steps, you’ve successfully hosted your project on GitHub Pages. Congratulations! Your project is now live and accessible to the world.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Just a few years ago, I was in your shoes—excited about building my first website but unsure how to share it with the world. Today, you’ve not only learned what Git and GitHub are but also how to use them to host your very own project.</p>
<p>Imagine your excitement when your project goes live, and you can share it with friends, family, and the global community. You've now set up Git, created a GitHub account, initialized a Git repository, and hosted your project on GitHub Pages. Each step has brought you closer to becoming a more confident and capable developer.</p>
<p>This is just the beginning. Git and GitHub have many more features for you to explore. As you continue building and sharing projects, you’ll discover new ways to collaborate and improve your workflow.</p>
<p>Keep experimenting, keep learning, and most importantly, keep coding. The world is waiting to see what you create next!</p>
<p>If you have any questions, feel free to find me on Twitter at <a target="_blank" href="https://twitter.com/sprucekhalifa">@sprucekhalifa</a>, and don’t forget to follow me for more tips and updates. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a TODO App from Scratch with React.js ]]>
                </title>
                <description>
                    <![CDATA[ If you're new to React.js and you're eager to dive into application development, then you've come to the right place! Join me in this tutorial as I walk you through building a basic TODO app from the ground up. The Importance of a TODO App for Beginn... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-todo-app-from-scratch-with-reactjs/</link>
                <guid isPermaLink="false">66d4614a706b9fb1c166b9af</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Fri, 12 Apr 2024 16:23:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot-2024-04-10-at-7.27.44-AM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're new to React.js and you're eager to dive into application development, then you've come to the right place!</p>
<p>Join me in this tutorial as I walk you through building a basic TODO app from the ground up.</p>
<h2 id="heading-the-importance-of-a-todo-app-for-beginners">The Importance of a TODO App for Beginners</h2>
<p>A TODO app serves as an ideal project for beginners to grasp the fundamentals of a new programming language or framework quickly. It provides a practical context for learning essential concepts while working towards a tangible outcome.</p>
<p>If you're embarking on your React.js journey, building a TODO app along with this tutorial could be the perfect starting point.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we begin, ensure you have basic knowledge of React.js and have Node.js and npm installed on your computer. If you haven't already, <a target="_blank" href="https://www.freecodecamp.org/news/how-to-install-react-a-step-by-step-guide/">take a moment to set up your development environment.</a></p>
<h2 id="heading-our-objective">Our Objective</h2>
<p>Our goal is to create a simple TODO app with features. Here's what we'll be aiming for:</p>
<ul>
<li><p>Adding New TODOs: Enable users to add new tasks to the list.</p>
</li>
<li><p>Editing and Deleting TODOs: Provide functionality to modify or remove existing tasks.</p>
</li>
<li><p>Marking TODOs as Completed: Allow users to indicate when tasks are finished.</p>
</li>
<li><p>Tracking Completed TODOs: Implement a feature to keep track of all completed tasks.</p>
</li>
</ul>
<p>Feel free to expand upon this list with additional features if you like. For the purpose of this tutorial, we'll focus on these core functionalities.</p>
<p>This is an example of the TODO app we are going to be building:</p>
<p><img src="https://lh7-us.googleusercontent.com/c6jXW1lvtqwDfabL0JRlt4C136nqXe-S5PRJKMywRKzuErt9sFnaXTbKl3tKFe2ZWEK2kIMSk1eDAEN5HtyFKbmsRo2nuXabVD-w8h1WNJnInEn5Gc3elHLGd0xOMonokRFA0tqiS8fxr64is1pFOwg" alt="Image" width="1200" height="770" loading="lazy"></p>
<p><em>A preview of our todo app</em></p>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><p><a target="_blank" href="“#How-to-Set-Up-Your-React-App”">How to Set Up Your React App</a></p>
</li>
<li><p><a target="_blank" href="“#How-to-Build-the-Components”">How to Build the Components</a></p>
<ul>
<li><p><a target="_blank" href="“#The-Header-Component”">The Header Component</a></p>
</li>
<li><p><a target="_blank" href="“#The-TODOHero-Component”">The TODOHero Component</a></p>
</li>
<li><p><a target="_blank" href="“#The-Form-Component”">The Form Component</a></p>
</li>
<li><p><a target="_blank" href="“#The-TODOList-Component”">The TODOList Component</a></p>
</li>
</ul>
</li>
<li><p><a target="_blank" href="“#Putting-it-All-Together”">Putting it All Together</a></p>
<ul>
<li><a target="_blank" href="“#The-Styling”">The Styling</a></li>
</ul>
</li>
<li><p><a target="_blank" href="“#Building-the-Functionality:How-to-add-todos”">Building the Functionality: How to add todos</a></p>
<ul>
<li><p><a target="_blank" href="“#A-Way-to-Store-the-Todo-Data”">A Way to Store the Todo Data</a></p>
</li>
<li><p><a class="post-section-overview" href="#What-Kind-of-Data-Do-We-Want-to-Store?">What Kind of Data Do We Want to Store?</a></p>
</li>
<li><p><a class="post-section-overview" href="#How-to-Pass-the-Todo-Data-to-Our-Components">How to Pass the Todo Data to Our-Components</a></p>
</li>
<li><p><a class="post-section-overview" href="#Adding-More-Todo-Data-to-Our-State">Adding More Todo Data to Our-State</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#How-to-Build-the-TODO-App's-Functionality">How to Build the TODO App's Functionality</a></p>
<ul>
<li><p><a class="post-section-overview" href="#How-to-Mark-Todos-as-Complete">How-to-Mark-Todos-as-Complete</a></p>
</li>
<li><p><a class="post-section-overview" href="#How-to-Edit-Todos">How to Edit Todos</a></p>
</li>
<li><p><a class="post-section-overview" href="#How-to-Delete-Todos">How to Delete Todos</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#How-to-Persist-Our-Todo-Data">How to Persist Our Todo Data</a></p>
<ul>
<li><p><a class="post-section-overview" href="#How-to-Persist-the-Todo-Data-to-localStorage">How to Persist the Todo Data to localStorage</a></p>
</li>
<li><p><a class="post-section-overview" href="#How-to-Read-the-Todo-Data-from-localStorage">How to Read the Todo Data from localStorage</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#summary">And-We’ve-Done-It.</a></p>
</li>
</ol>
<h2 id="heading-how-to-set-up-your-react-app">How to Set Up Your React App</h2>
<p>In 2024, using a framework like Next.js or Remix is a recommended approach for initiating a React project. Either framework will suffice – so just choose the one you're most comfortable with. For this tutorial, we'll be using Next.js.</p>
<p>To create a React app with Next.js, navigate to your preferred directory and run the following command:</p>
<pre><code class="lang-bash">npx create-next-app@latest
</code></pre>
<p>Note: We won't be using TypeScript and TailwindCSS for this project, so you can proceed with the default settings.</p>
<p>Once the installation is complete, navigate into your newly created app directory (I've named mine 'todo') and start the development server by running:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> todo
npm run dev
<span class="hljs-comment">## or with yarn</span>
<span class="hljs-built_in">cd</span> todo
yarn run dev
</code></pre>
<p>With your development server up and running, we're ready to begin crafting our TODO app!</p>
<h2 id="heading-how-to-build-the-components">How to Build the Components</h2>
<p>In React, we build UIs out of components. Our TODO app's UI consists of several parts. Let's break them down:</p>
<h3 id="heading-the-header-component">The Header Component</h3>
<p>The Header component serves to display the title of our app. Rather than directly embedding HTML, we'll build this functionality within a React component.</p>
<p>Start by creating a directory for our components:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># In the root directory of your project, create a new directory</span>
mkdir src/components
<span class="hljs-comment"># Navigate into the directory</span>
<span class="hljs-built_in">cd</span> src/components
<span class="hljs-comment"># Create a new file for the Header component</span>
touch Header.jsx
</code></pre>
<p>Components in React are essentially JavaScript functions that return HTML. In our Header.jsx file, define a function that returns the HTML content for our Header component:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/Header.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Header</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">""</span> /&gt;</span> 
      <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>TODO<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Header;
</code></pre>
<p>We're exporting the Header function so that we can utilize it throughout our project.</p>
<h3 id="heading-the-todohero-component">The TODOHero Component</h3>
<p>The TODO Hero Component plays a pivotal role in our application. It serves as the section where we provide an overview of the total number of todos and the number of completed tasks.</p>
<p><img src="https://lh7-us.googleusercontent.com/BEGn3mOpp0K5yZyALAFqwNASN8UDcJJwc1JYugAKgRECnsOAsv2la6O7nPtSJXmOffXc-dre7Ftu6aJFUrWgfV9AychKvECOTspY6vGdiMtQZ2O5uufi8e4UaC2I1JgchsHvN4LlegRG9K6cteGu1jA" alt="Image" width="1600" height="684" loading="lazy"></p>
<p><em>An image showing the</em> <code>TODOHero</code> component</p>
<p>Unlike the header component, which remains static throughout our app usage, the <code>TODOHero</code> component is dynamic. It continuously updates based on the number of completed todos and the total number of todos.</p>
<p>When building components, it's important to identify dynamic parts early on. In React, we achieve this by passing arguments, called props, to our components.</p>
<p>Let's create the <code>TODOHero</code> component. First, make sure you're in the src/components directory:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> src/components
</code></pre>
<p>Now, create a new file for the <code>TODOHero</code> component:</p>
<pre><code class="lang-bash">touch TODOHero.jsx
</code></pre>
<p>In TODOHero.jsx, define a function that takes props as arguments:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOHero.jsx</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TODOHero</span>(<span class="hljs-params">{ todos_completed, total_todos }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">section</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Task Done<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Keep it up<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        {todos_completed}/{total_todos}
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">section</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TODOHero;
</code></pre>
<p>This function returns HTML content for our TODOHero component. We're using props to dynamically update the number of completed todos and the total number of todos.</p>
<h3 id="heading-the-form-component">The Form Component</h3>
<p>Our Form component is going to be a simple input with a submit button, so go ahead and create a new component</p>
<pre><code class="lang-bash">touch src/components/Form.jsx
</code></pre>
<p>Like I said, this is going to be a very simple form: just an input with a submit button. The label is for accessibility.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/Form.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Form</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    <span class="hljs-comment">// reset the form</span>
    event.target.reset();
  };
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"todo"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">name</span>=<span class="hljs-string">"todo"</span>
          <span class="hljs-attr">id</span>=<span class="hljs-string">"todo"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Write your next task"</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"visually-hidden"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">""</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Form;
</code></pre>
<p>We've added an <code>onSubmit</code> event to the form with a <code>handleSubmit</code> event handler. The <code>event.preventDefault()</code> prevents the form from submitting and reloading the entire app. Lastly, we reset the form with <code>event.target.reset()</code>.</p>
<h3 id="heading-the-todolist-component">The TODOList Component</h3>
<p>Lastly, let's create the List component. Start by creating a new component file named TODOList.jsx:</p>
<pre><code class="lang-bash">touch src/components/TODOList.jsx
</code></pre>
<p>The list itself is a straightforward ordered list:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TODOList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ol</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_list"</span>&gt;</span>{/* <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span> list goes here */}<span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span>;
}
export default TODOList;</span>
</code></pre>
<p>The list items will be generated dynamically from the todo data. But before we proceed, let's create a separate component for the list item.</p>
<p>In React, nearly everything is a component, so we'll create the <code>Item</code> component alongside the <code>TODOList</code> component:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Item</span>(<span class="hljs-params">{ item }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{item?.id}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_items_left"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"11.998"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"11.998"</span> <span class="hljs-attr">fillRule</span>=<span class="hljs-string">"nonzero"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"9.998"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{item?.title}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_items_right"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"visually-hidden"</span>&gt;</span>Edit<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">""</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"visually-hidden"</span>&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">""</span> /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
}
</code></pre>
<p>The list item itself is simply an <code>&lt;li&gt;</code> element with buttons for editing and deleting tasks. We've ensured that the <code>&lt;li&gt;</code> itself is not clickable, following the principle that "anything clickable on the web should either be a button or a link".</p>
<p>Now, we can use the <code>Item</code> component within our list:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TODOList</span>(<span class="hljs-params">{ todos }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ol</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_list"</span>&gt;</span>
      {todos &amp;&amp; todos.length &gt; 0 ? (
        todos?.map((item, index) =&gt; <span class="hljs-tag">&lt;<span class="hljs-name">Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">item</span>=<span class="hljs-string">{item}</span> /&gt;</span>)
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Seems lonely in here, what are you up to?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TODOList;
</code></pre>
<p>With these components in place, our TODO app's UI is fully constructed.</p>
<h2 id="heading-putting-it-all-together">Putting it All Together</h2>
<p>So far, we've created four separate components, each of which doesn't do much on its own. Now, we need to render these components in our index page.</p>
<p>In Next.js, pages are located inside the src/app directory, and the index page is typically named page.js.</p>
<p>First, let's empty the contents of the file as we won't need anything inside it:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> -n &gt; src/app/page.js
</code></pre>
<p>Next, import all the components we've created and utilize them inside the page.js file as shown below:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/app/page.js</span>

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Form <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Form"</span>;
<span class="hljs-keyword">import</span> Header <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Header"</span>;
<span class="hljs-keyword">import</span> TODOHero <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TODOHero"</span>;
<span class="hljs-keyword">import</span> TODOList <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TODOList"</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TODOHero</span> <span class="hljs-attr">todos_completed</span>=<span class="hljs-string">{0}</span> <span class="hljs-attr">total_todos</span>=<span class="hljs-string">{0}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TODOList</span> <span class="hljs-attr">todos</span>=<span class="hljs-string">{[]}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>By viewing the output in your browser, it should resemble something like this:</p>
<p><img src="https://lh7-us.googleusercontent.com/iarew4c0BX773LQXr_pmwOpUK7YFQt-shtsuYPVfqKI9_Z6JsBMj90A3BvE_WFKK37jxoAyG038xHeuvsJsAhhky6D-tH_VzVKqfvjlT1TkYv_v52VDNEl7IbrgjL_c439Ws8JsMO887a6ipk3H_4Pk" alt="Image" width="1600" height="1027" loading="lazy"></p>
<p><em>A preview of our app without CSS</em></p>
<h3 id="heading-the-styling">The Styling</h3>
<p>For styling, we'll stick to good old CSS. Let's create a styles.css file to hold our styles:</p>
<pre><code class="lang-bash">touch src/app/styles.css
</code></pre>
<p>Also, delete all the CSS files that came with installing Next.js as we won't need them:</p>
<pre><code class="lang-bash">rm src/app/page.module.css &amp;&amp; src/app/globals.css
</code></pre>
<p>Now, you can add your CSS rules in the styles.css file. Though not perfect, the following CSS should suffice for our simple example:</p>
<pre><code class="lang-css">*,
*<span class="hljs-selector-pseudo">::after</span>,
*<span class="hljs-selector-pseudo">::before</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">font-family</span>: inherit;
  <span class="hljs-attribute">box-sizing</span>: border-box;
}
<span class="hljs-selector-tag">html</span>,
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: sans-serif;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0d0d0d</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
}
<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">cursor</span>: pointer;
}
<span class="hljs-selector-class">.visually-hidden</span> {
  <span class="hljs-attribute">position</span>: absolute <span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">clip</span>: <span class="hljs-built_in">rect</span>(<span class="hljs-number">1px</span>, <span class="hljs-number">1px</span>, <span class="hljs-number">1px</span>, <span class="hljs-number">1px</span>);
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">0</span> <span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">1px</span> <span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">1px</span> <span class="hljs-meta">!important</span>;
  <span class="hljs-attribute">overflow</span>: hidden;
  <span class="hljs-attribute">white-space</span>: nowrap;
}
<span class="hljs-selector-class">.text_large</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">32px</span>;
}
<span class="hljs-selector-class">.text_small</span> {
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">24px</span>;
}
<span class="hljs-selector-class">.wrapper</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">70%</span>;
}
<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">510px</span>) {
  <span class="hljs-selector-class">.wrapper</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  }
  <span class="hljs-selector-tag">header</span> {
    <span class="hljs-attribute">justify-content</span>: center;
  }
}
<span class="hljs-selector-tag">header</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: flex-start;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">42px</span>;
}
<span class="hljs-selector-class">.todohero_section</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#c2b39a</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: space-around;
  <span class="hljs-attribute">align-self</span>: center;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">90%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">455px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">11px</span>;
}
<span class="hljs-selector-class">.todohero_section</span> <span class="hljs-selector-tag">div</span><span class="hljs-selector-pseudo">:last-child</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#88ab33</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">150px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">75px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">48px</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">text-align</span>: center;
}
<span class="hljs-selector-class">.form</span> {
  <span class="hljs-attribute">align-self</span>: center;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">97%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">455px</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">38px</span>;
}
<span class="hljs-selector-class">.form</span> <span class="hljs-selector-tag">label</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">90%</span>;
}
<span class="hljs-selector-class">.form</span> <span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#1f2937</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">outline</span>: none;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">11px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">12px</span>;
}
<span class="hljs-selector-class">.form</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">10%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">11px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#88ab33</span>;
  <span class="hljs-attribute">border</span>: none;
}
<span class="hljs-selector-class">.todo_list</span> {
  <span class="hljs-attribute">align-self</span>: center;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">97%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">455px</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">27px</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">27px</span>;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">27px</span>;
}
<span class="hljs-selector-class">.todo_item</span>,
<span class="hljs-selector-class">.edit-form</span> <span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">70px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">455px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#c2b39a</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0d0d0d</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">12px</span>;
}
<span class="hljs-selector-class">.edit-form</span> <span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">outline</span>: transparent;
  <span class="hljs-attribute">width</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">100%</span> - <span class="hljs-number">14px</span>);
  <span class="hljs-attribute">height</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">100%</span> - <span class="hljs-number">12px</span>);
  <span class="hljs-attribute">border</span>: transparent;
}
<span class="hljs-selector-class">.todo_items_left</span>,
<span class="hljs-selector-class">.todo_items_right</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
}
<span class="hljs-selector-class">.todo_items_left</span> {
  <span class="hljs-attribute">background-color</span>: transparent;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">12px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
}
<span class="hljs-selector-class">.todo_items_right</span> {
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">4px</span>;
}
<span class="hljs-selector-class">.todo_items_right</span> <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: transparent;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border</span>: none;
}
<span class="hljs-selector-class">.todo_items_right</span> <span class="hljs-selector-tag">button</span> <span class="hljs-selector-tag">svg</span> {
  <span class="hljs-attribute">fill</span>: <span class="hljs-number">#c2b39a</span>;
}
</code></pre>
<p>Lastly, we need to import the CSS file in our layout. Open the layout.js file located right next to the page.js and import the CSS file as demonstrated below:</p>
<p><img src="https://lh7-us.googleusercontent.com/BMQnzUwBP_ksPvXvMdG2WgpsLZCA4xrucsHmuAg16JCmciXLh8CREGOIbCmrGPKtR_uEJYG50bL0SUw7Yb_oj2fnRsgAfnSIwKWTyOtIhSje_p7HPe818ZvXFbey54EOlNibmABCOkmkTiaF-zzFptY" alt="Image" width="1172" height="648" loading="lazy"></p>
<p><em>An image showing how to import styles.css file in our component</em></p>
<p>Upon previewing the app again, it should now reflect the applied styles:</p>
<p><img src="https://lh7-us.googleusercontent.com/kJ9zqWtpAHFcR0zxgQr9HOVOlQiCUXRFDoyMRn4_erG9DTGOTZ3x1lS3BvhhyY3h3rhuvIuLvQ2v5IQshQsc7rDl6Kjsqjspi4EdhoWKgxjejerJ9WRoJXvU78eDnjTB90WIMky31lUemGB1KlMQqXw" alt="Image" width="1600" height="1027" loading="lazy"></p>
<p><em>An image showing the preview of our app after adding CSS</em></p>
<h2 id="heading-building-the-functionality-how-to-add-todos">Building the Functionality: How to add todos</h2>
<p>At this stage, we've crafted a visually appealing todo app, but it lacks functionality. Let's change that in this section.</p>
<h3 id="heading-a-way-to-store-the-todo-data">A Way to Store the Todo Data</h3>
<p>Firstly, we need a method to store our todo data. In React, this is accomplished using state—a JavaScript object that holds information about a component's state.</p>
<p>React provides a hook called <code>useState()</code>, which enables us to manage state in our React apps. But in Next.js, before utilizing <code>useState</code>, you need to specify that the component is a client component.</p>
<p>Add the following code to the top of your src/app/page.js file:</p>
<pre><code class="lang-js"><span class="hljs-string">"use client"</span>;
</code></pre>
<p>As depicted in the image below:</p>
<p><img src="https://lh7-us.googleusercontent.com/-K5nq04GCngiUGJEbtSQhNprJ0eTPPzapT8MjCcEYSRyEXq5Tz8zT4hgqwSd5wcwgZNgnkVA_fpraJhxJog3aZiynE9CdvzO0VGF-wHTpodvilFYNW7uICnAD9zdqvuxVbbZQ3pMizcbiPoD78kb0Zw" alt="Image" width="852" height="258" loading="lazy"></p>
<p><em>An image showing how to add "use client" to the top of our page.js</em></p>
<p>Now, we can use the <code>useState</code> hook to create a state for our todo data:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/app/page.js</span>

<span class="hljs-string">"use client"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Form <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Form"</span>;
<span class="hljs-comment">// Add imports for other components</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [todos, setTodos] = React.useState([]);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span></span>
    <span class="hljs-comment">// Add other components here</span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>In the above code snippet, you'll notice that <code>useState</code> initially holds an empty array. It's important to understand that <code>useState</code> returns two values: <code>todos</code> and <code>setTodos</code> (you can name these anything you prefer).</p>
<p>The first value, <code>todos</code>, holds the current value of the state, while <code>setTodos</code> (the second value) is a function used to update the state. Clear so far?</p>
<h3 id="heading-what-kind-of-data-do-we-want-to-store">What Kind of Data Do We Want to Store?</h3>
<p>Now that we have a means to store our data, let's define the type of data we intend to store. Essentially, it will be an array of objects, where each object holds the necessary information to render our list of todos:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [todos, setTodos] = React.useState([
{ <span class="hljs-comment">/* Object */</span> },
{ <span class="hljs-comment">/* Object */</span> },
{ <span class="hljs-comment">/* Object */</span> },
]);
</code></pre>
<p>Each object in the array will have the following structure:</p>
<pre><code class="lang-js">{
<span class="hljs-attr">title</span>: <span class="hljs-string">"Some task"</span>,  <span class="hljs-comment">// string</span>
<span class="hljs-attr">id</span>: self.crypto.randomUUID(), <span class="hljs-comment">// string</span>
<span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span> <span class="hljs-comment">// boolean</span>
}
</code></pre>
<p>Here, <code>self.crypto.randomUUID()</code> is a method that allows the browser to generate unique IDs for each todo item. If you view the console, you'll observe that the generated IDs are indeed unique.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot-2024-04-04-at-9.47.22-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>console.log of our todo data</em></p>
<p>This structure ensures that each todo item has a title, a unique identifier (id), and a Boolean value indicating whether the task is completed (<code>is_completed</code>).</p>
<h3 id="heading-how-to-pass-the-todo-data-to-our-components">How to Pass the Todo Data to Our Components</h3>
<p>In React, there's a concept called state sharing, which allows children components to access the state of their parent components. This means that the todo state we created earlier can be shared among all our components.</p>
<p>The first place we need the data from the state is in our List Component. Let's pass the state to the List component:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/app/page.js</span>

<span class="hljs-string">"use client"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-comment">// import other components</span>
<span class="hljs-keyword">import</span> TODOList <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TODOList"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [todos, setTodos] = React.useState([
    { <span class="hljs-attr">title</span>: <span class="hljs-string">"Some task"</span>, <span class="hljs-attr">id</span>: self.crypto.randomUUID(), <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span> },
    {
      <span class="hljs-attr">title</span>: <span class="hljs-string">"Some other task"</span>,
      <span class="hljs-attr">id</span>: self.crypto.randomUUID(),
      <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">true</span>,
    },
    { <span class="hljs-attr">title</span>: <span class="hljs-string">"last task"</span>, <span class="hljs-attr">id</span>: self.crypto.randomUUID(), <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span> },
  ]);
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
      ...
      <span class="hljs-tag">&lt;<span class="hljs-name">TODOList</span> <span class="hljs-attr">todos</span>=<span class="hljs-string">{todos}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>We already made provisions in our List component to receive a <code>todos</code> prop:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TODOList</span>(<span class="hljs-params">{ todos }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ol</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_list"</span>&gt;</span>
      {todos &amp;&amp; todos.length &gt; 0 ? (
        todos?.map((item, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">item</span>=<span class="hljs-string">{item}</span> <span class="hljs-attr">setTodos</span>=<span class="hljs-string">{setTodos}</span> /&gt;</span>
        ))
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Seems lonely in here, what are you up to?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span></span>
  );
}
</code></pre>
<p>Now, the todos prop will be populated by the data from our state, and without any further ado, this will work. Here’s an image showing the List created from our todos data:</p>
<p><img src="https://lh7-us.googleusercontent.com/oqqO8NpZ3Mzdl2Ydc9MYlzYZPtvNstvVdB8hrjhF4hra41cwpSYNN0QwbsPCAi1cUDBGAR-lcPpso8sMdiAgzvU-JjHEV-Cn3FqvNkxqekulirAAGbrpDeGMwtSJyQGcqnydhvOqDSbjPgV3NpQYmM0" alt="Image" width="1600" height="1027" loading="lazy"></p>
<p><em>An image showing a list of our todos</em></p>
<p>The other place we need the data is in our <code>TODOHero</code> component. We don’t need all of the data in that component – we just need to count the total number of todos and the number of completed todos:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/app/page.js</span>

<span class="hljs-string">"use client"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-comment">// import other components</span>
<span class="hljs-keyword">import</span> TODOHero <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TODOHero"</span>;
<span class="hljs-keyword">import</span> TODOList <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TODOList"</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [todos, setTodos] = React.useState([
    { <span class="hljs-attr">title</span>: <span class="hljs-string">"Some task"</span>, <span class="hljs-attr">id</span>: self.crypto.randomUUID(), <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span> },
    <span class="hljs-comment">// add other dummy data</span>
  ]);
  <span class="hljs-keyword">const</span> todos_completed = todos.filter(
    <span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo.is_completed === <span class="hljs-literal">true</span>
  ).length;
  <span class="hljs-keyword">const</span> total_todos = todos.length;
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TODOHero</span> <span class="hljs-attr">todos_completed</span>=<span class="hljs-string">{todos_completed}</span> <span class="hljs-attr">total_todos</span>=<span class="hljs-string">{total_todos}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TODOList</span> <span class="hljs-attr">todos</span>=<span class="hljs-string">{todos}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Here, the JavaScript filter method is used to filter out all the todos with <code>is_completed</code> set to true, and then we get the length. The <code>total_todos</code> is simply the length of the entire array.</p>
<p>Here’s an image showing the <code>TODOHero</code> component with updated values:</p>
<p><img src="https://lh7-us.googleusercontent.com/zDgqM8GZi9Wrr80GIWPFyq9D1kSOFXqZ4zDkKUTtWzayHnABJ7LYgvQi9xrukNEdJg2jbg7_Co07LfZJr7bsVFw1cytBN1INq5uv4AM87iHrn5B5KYtuY2wn2HRh0bMRu2PBLcNEoS8p1H_F5oS2kko" alt="Image" width="1600" height="1027" loading="lazy"></p>
<p><em>An image showing the updated TODOHero component</em></p>
<h3 id="heading-adding-more-todo-data-to-our-state">Adding More Todo Data to Our State</h3>
<p>Currently, our todo app displays todos from our dummy data:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [todos, setTodos] = React.useState([
  { <span class="hljs-attr">title</span>: <span class="hljs-string">"Some task"</span>, <span class="hljs-attr">id</span>: self.crypto.randomUUID(), <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span> },
  {
    <span class="hljs-attr">title</span>: <span class="hljs-string">"Some other task"</span>,
    <span class="hljs-attr">id</span>: self.crypto.randomUUID(),
    <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">true</span>,
  },
  { <span class="hljs-attr">title</span>: <span class="hljs-string">"last task"</span>, <span class="hljs-attr">id</span>: self.crypto.randomUUID(), <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span> },
]);
</code></pre>
<p>But the purpose of creating a Form component was to enable us to create new todos ourselves, not rely on dummy data.</p>
<p>The good news is that just as we have access to the todo state data, we can also update the state of a parent from a children component. This means we can pass the function used to update the state, <code>setTodos</code>, to our Form component:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/app/page.js</span>

<span class="hljs-string">"use client"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Form <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Form"</span>;
<span class="hljs-comment">// import other components</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [todos, setTodos] = React.useState([
    { <span class="hljs-attr">title</span>: <span class="hljs-string">"Some task"</span>, <span class="hljs-attr">id</span>: self.crypto.randomUUID(), <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span> },
    <span class="hljs-comment">// add other dummy data</span>
  ]);

  ...
  return (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
      ...
      <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">setTodos</span>=<span class="hljs-string">{setTodos}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TODOList</span> <span class="hljs-attr">todos</span>=<span class="hljs-string">{todos}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>With access to the <code>setTodos</code> function in our Form component, we can now add new todos to our state when we submit the form:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/Form.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Form</span>(<span class="hljs-params">{ setTodos }</span>) </span>{
  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    <span class="hljs-keyword">const</span> value = event.target.todo.value;
    setTodos(<span class="hljs-function">(<span class="hljs-params">prevTodos</span>) =&gt;</span> [
      ...prevTodos,
      { <span class="hljs-attr">title</span>: value, <span class="hljs-attr">id</span>: self.crypto.randomUUID(), <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span> },
    ]);
    event.target.reset();
  };
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleSubmit}</span>&gt;</span>
      …
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Form;
</code></pre>
<p>The code snippet below is where the magic happens:</p>
<pre><code class="lang-js">setTodos(<span class="hljs-function">(<span class="hljs-params">prevTodos</span>) =&gt;</span> [
  ...prevTodos,
  { <span class="hljs-attr">title</span>: value, <span class="hljs-attr">id</span>: self.crypto.randomUUID(), <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span> },
]);
</code></pre>
<p>It is the equivalent of doing the following in plain JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> prevTodos = [];

prevTodos.push({
  <span class="hljs-attr">title</span>: value,
  <span class="hljs-attr">id</span>: self.crypto.randomUUID(),
  <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span>,
});
</code></pre>
<p>Now that we can add new todos to our state by ourselves, we can get rid of the dummy data. We no longer need it. Let's go back to using an empty array:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [todos, setTodos] = React.useState([]);
</code></pre>
<p>Now that we're through with the first part, we can add todos as we please. Here’s a video demonstrating it working:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/bUqtCC8qBwI" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-how-to-build-the-todo-apps-functionality">How to Build the TODO App's Functionality</h2>
<h3 id="heading-how-to-mark-todos-as-complete">How to Mark Todos as Complete</h3>
<p>In our List component, we constructed an <code>&lt;li&gt;</code> element with buttons. Now, we're going to attach an <code>onClick</code> event handler to the first button.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Item</span>(<span class="hljs-params">{ item }</span>) </span>{
  <span class="hljs-keyword">const</span> completeTodo = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// perform some action</span>
  };
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{item?.id}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_item"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{completeTodo}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_items_left"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"11.998"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"11.998"</span> <span class="hljs-attr">fillRule</span>=<span class="hljs-string">"nonzero"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"9.998"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{item?.title}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_items_right"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
}
</code></pre>
<p>When we click on this button and the completeTodo handler is invoked, our objective is to:</p>
<ul>
<li><p>Filter the data to find the todo that was clicked.</p>
</li>
<li><p>Modify the data and set the <code>is_completed</code> value to true.</p>
</li>
</ul>
<p>Before we can proceed with data modification, we need access to the <code>setTodo</code> function in our <code>&lt;Item /&gt;</code> component. Fortunately, React allows state to be passed down to grandchildren components.</p>
<p>This means we can pass the <code>setTodo</code> function from the <code>&lt;List /&gt;</code> component to our <code>&lt;Item /&gt;</code> component:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/app/page.js</span>

<span class="hljs-string">"use client"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-comment">// import other components</span>
<span class="hljs-keyword">import</span> TODOList <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TODOList"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [todos, setTodos] = React.useState([]);

...

  return (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
      ...
      <span class="hljs-tag">&lt;<span class="hljs-name">TODOList</span> <span class="hljs-attr">todos</span>=<span class="hljs-string">{todos}</span> <span class="hljs-attr">setTodos</span>=<span class="hljs-string">{setTodos}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>Then, within our <code>&lt;List /&gt;</code> component, we pass the <code>setTodo</code> function to our <code>&lt;Item /&gt;</code> component:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TODOList</span>(<span class="hljs-params">{ todos, setTodos }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ol</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_list"</span>&gt;</span>
      {todos &amp;&amp; todos.length &gt; 0 ? (
        todos?.map((item, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">item</span>=<span class="hljs-string">{item}</span> <span class="hljs-attr">setTodos</span>=<span class="hljs-string">{setTodos}</span> /&gt;</span>
        ))
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Seems lonely in here, what are you up to?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span></span>
  );
}
</code></pre>
<p>Now, within our <code>&lt;Item /&gt;</code> component, we can use the <code>setTodos</code> function to update the todo's <code>is_completed</code> status when the button is clicked:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Item</span>(<span class="hljs-params">{ item, setTodos }</span>) </span>{
  <span class="hljs-keyword">const</span> completeTodo = <span class="hljs-function">() =&gt;</span> {
    setTodos(<span class="hljs-function">(<span class="hljs-params">prevTodos</span>) =&gt;</span>
      prevTodos.map(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span>
        todo.id === item.id
          ? { ...todo, <span class="hljs-attr">is_completed</span>: !todo.is_completed }
          : todo
      )
    );
  };
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{item?.id}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_item"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_items_left"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{completeTodo}</span>&gt;</span>
        ...
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_items_right"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span></span>
  );
}
</code></pre>
<p>Now, clicking on the first button within the todo item will toggle its completion status, effectively modifying the todo data.</p>
<p>When a todo is marked as completed, we want to enhance its visual representation. This includes adding a fill to the SVG circle beside the todo title, creating the illusion that the todo is completed. Also, we want to add a strike-through to the text to signify completion.</p>
<pre><code class="lang-js">&lt;button className=<span class="hljs-string">"todo_items_left"</span> onClick={completeTodo}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">{item.is_completed</span> ? "#<span class="hljs-attr">22C55E</span>" <span class="hljs-attr">:</span> "#<span class="hljs-attr">0d0d0d</span>"}&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"11.998"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"11.998"</span> <span class="hljs-attr">fillRule</span>=<span class="hljs-string">"nonzero"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"9.998"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{item.is_completed</span> ? { <span class="hljs-attr">textDecoration:</span> "<span class="hljs-attr">line-through</span>" } <span class="hljs-attr">:</span> {}}&gt;</span>
    {item?.title}
  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>
&lt;/button&gt;;
</code></pre>
<p>In the above code snippet, the button's color changes based on the completion status of the todo item. If the item is completed (<code>is_completed</code> is true), the SVG circle fills with a green color – otherwise, it fills with a dark color. Also, the todo title text receives a line-through style if the todo is completed, indicating its completion visually.</p>
<p>And now everything is working perfectly:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/MJ57XGaOimI" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h3 id="heading-how-to-edit-todos">How to Edit Todos</h3>
<p>When editing todos, we want to have a form in which we can edit the title of the todo. When the edit button is clicked we want to swap out the everything in the <code>&lt;li&gt;</code> and have a form instead:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Item</span>(<span class="hljs-params">{ item, setTodos }</span>) </span>{
  <span class="hljs-keyword">const</span> [editing, setEditing] = React.useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> inputRef = React.useRef(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> completeTodo = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// mark todo as complete</span>
  };
  <span class="hljs-keyword">const</span> handleEdit = <span class="hljs-function">() =&gt;</span> {
    setEditing(<span class="hljs-literal">true</span>);
  };
  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (editing &amp;&amp; inputRef.current) {
      inputRef.current.focus();
      <span class="hljs-comment">// position the cursor at the end of the text</span>
      inputRef.current.setSelectionRange(
        inputRef.current.value.length,
        inputRef.current.value.length
      );
    }
  }, [editing]);
  <span class="hljs-keyword">const</span> handleInpuSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
    event.preventDefault();
    setEditing(<span class="hljs-literal">false</span>);
  };
  <span class="hljs-keyword">const</span> handleInputBlur = <span class="hljs-function">() =&gt;</span> {
    setEditing(<span class="hljs-literal">false</span>);
  };
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{item?.id}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_item"</span>&gt;</span>
      {editing ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"edit-form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleInpuSubmit}</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"edit-todo"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
              <span class="hljs-attr">ref</span>=<span class="hljs-string">{inputRef}</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
              <span class="hljs-attr">name</span>=<span class="hljs-string">"edit-todo"</span>
              <span class="hljs-attr">id</span>=<span class="hljs-string">"edit-todo"</span>
              <span class="hljs-attr">defaultValue</span>=<span class="hljs-string">{item?.title}</span>
              <span class="hljs-attr">onBlur</span>=<span class="hljs-string">{handleInputBlur}</span>
              <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleInputChange}</span>
            /&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_items_left"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{completeTodo}</span>&gt;</span>
            ...
          <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_items_right"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleEdit}</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>&gt;</span>...<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/&gt;</span></span>
      )}
    &lt;/li&gt;
  );
}
</code></pre>
<p>I know the code above is quite a handful. Well, that’s because we are doing a lot here – but the first thing we did was create a state:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [editing, setEditing] = React.useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>When the edit button is clicked we set the value of our editing state to true, which will render our form:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleEdit = <span class="hljs-function">() =&gt;</span> {
  setEditing(<span class="hljs-literal">true</span>);
};
</code></pre>
<p>Now, when we submit the edit todo form by pressing enter, we also want to set the variable back to false so we can get back our list:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleInpuSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.preventDefault();
  setEditing(<span class="hljs-literal">false</span>);
};
</code></pre>
<p>When we mouse out of the edit form, we also want to set the state back to false:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleInputBlur = <span class="hljs-function">() =&gt;</span> {
  setEditing(<span class="hljs-literal">false</span>);
};
</code></pre>
<p>Another thing we want to do is to focus the input once editing is set to true:</p>
<pre><code class="lang-jsx">React.useEffect(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">if</span> (editing &amp;&amp; inputRef.current) {
    inputRef.current.focus();
    <span class="hljs-comment">// position the cursor at the end of the text</span>
    inputRef.current.setSelectionRange(
      inputRef.current.value.length,
      inputRef.current.value.length
    );
  }
}, [editing]);
</code></pre>
<p>The edit todo itself has a single input field with an <code>onChange</code> event. As we edit the title in the input field, we want to modify the current todo with the updated title:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleInputChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  setTodos(<span class="hljs-function">(<span class="hljs-params">prevTodos</span>) =&gt;</span>
    prevTodos.map(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span>
      todo.id === item.id ? { ...todo, <span class="hljs-attr">title</span>: e.target.value } : todo
    )
  );
};
</code></pre>
<p>The JavaScript <code>array.map()</code> method is perfect for this because it returns a new array with the same number of elements after modifying the title.</p>
<p>Here’s a video of it working seamlessly:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/YRGq0SV7K_c" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h3 id="heading-how-to-delete-todos">How to Delete Todos</h3>
<p>Deleting todos is a straightforward process. When the delete button is clicked, we filter out the todo that triggered the delete event from the todo list.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-keyword">const</span> handleDelete = <span class="hljs-function">() =&gt;</span> {
  setTodos(<span class="hljs-function">(<span class="hljs-params">prevTodos</span>) =&gt;</span> prevTodos.filter(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo.id !== item.id));
};
</code></pre>
<p>Don’t forget to add an onClick event to the delete button:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Item</span>(<span class="hljs-params">{ item, setTodos }</span>) </span>{
  ...
    const handleDelete = <span class="hljs-function">() =&gt;</span> {
    setTodos(<span class="hljs-function">(<span class="hljs-params">prevTodos</span>) =&gt;</span> prevTodos.filter(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo.id !== item.id));
  };
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{item?.id}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_item"</span>&gt;</span>
      {editing ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"edit-form"</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleInpuSubmit}</span>&gt;</span>
          ...
        <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
      ) : (
        <span class="hljs-tag">&lt;&gt;</span>
          …
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_items_right"</span>&gt;</span>
            …
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleDelete}</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"visually-hidden"</span>&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">svg</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">d</span>=<span class="hljs-string">""</span> /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/&gt;</span></span>
      )}
    &lt;/li&gt;
  );
}
</code></pre>
<p>And voilà! It just works like a charm:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/YMEmxMr1KEY" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-how-to-persist-our-todo-data">How to Persist Our Todo Data</h2>
<p>Up to this point, our todo data has been stored solely in the application's state:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> [todos, setTodos] = React.useState([]);
</code></pre>
<p>While this approach works, it presents a challenge: when the app is reloaded, all todo data is lost.</p>
<p>When it comes to persisting data, we typically think of databases. Storing our todo data in a database offers several advantages, such as easy access from any device. But there's an alternative: localStorage.</p>
<p>LocalStorage is a browser-based storage system. It has some limitations, like a 5MB storage cap and data accessibility restricted to the browser where it's stored. Despite these drawbacks, we'll use localStorage in this tutorial for simplicity's sake.</p>
<h3 id="heading-how-to-persist-the-todo-data-to-localstorage">How to Persist the Todo Data to localStorage</h3>
<p>Currently, when we add a new todo, we're only updating the todo state in our Form component:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/components/Form.jsx</span>

<span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.preventDefault();
  <span class="hljs-keyword">const</span> value = event.target.todo.value;
  setTodos(<span class="hljs-function">(<span class="hljs-params">prevTodos</span>) =&gt;</span> [
    ...prevTodos,
    { <span class="hljs-attr">title</span>: value, <span class="hljs-attr">id</span>: self.crypto.randomUUID(), <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span> },
  ]);
  event.target.reset();
};
</code></pre>
<p>We still want to keep this, but at the same time we want to add the same data to localStorage, so we’ll modify the code above to look like this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/components/Form.jsx </span>

<span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.preventDefault();
  <span class="hljs-keyword">const</span> value = event.target.todo.value;
  <span class="hljs-keyword">const</span> newTodo = {
    <span class="hljs-attr">title</span>: value,
    <span class="hljs-attr">id</span>: self.crypto.randomUUID(),
    <span class="hljs-attr">is_completed</span>: <span class="hljs-literal">false</span>,
  };
  <span class="hljs-comment">// Update todo state</span>
  setTodos(<span class="hljs-function">(<span class="hljs-params">prevTodos</span>) =&gt;</span> [...prevTodos, newTodo]);
  <span class="hljs-comment">// Store updated todo list in local storage</span>
  <span class="hljs-keyword">const</span> updatedTodoList = <span class="hljs-built_in">JSON</span>.stringify([...todos, newTodo]);
  <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"todos"</span>, updatedTodoList);
  event.target.reset();
};
</code></pre>
<p>Did I mention that you can only store strings in localStorage? We can’t store an array or object in localStorage. That's why we first convert our array of todo data to a string:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> updatedTodoList = <span class="hljs-built_in">JSON</span>.stringify([...prevTodos, newTodo]);
</code></pre>
<p>And then finally we persist the data in localStorage with this code:</p>
<pre><code class="lang-js"><span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">'todos'</span>, updatedTodoList);
</code></pre>
<p>You’ll notice we used our <code>todos</code> state data in our <code>&lt;Form /&gt;</code> component:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> updatedTodoList = <span class="hljs-built_in">JSON</span>.stringify([...todos, newTodo]);
</code></pre>
<p>So don’t forget to pass the todo state to the component:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/app/page.js</span>

&lt;Form todos={todos} setTodos={setTodos} /&gt;
</code></pre>
<p>Also, since we can edit and delete todos in our app, we need to update the data in localStorage accordingly. First, pass the todos data to our <code>&lt;Item /&gt;</code> component:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TODOList</span>(<span class="hljs-params">{ todos, setTodos }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ol</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"todo_list"</span>&gt;</span>
      {todos &amp;&amp; todos.length &gt; 0 ? (
        todos?.map((item, index) =&gt; (
        // pass the todos to <span class="hljs-tag">&lt;<span class="hljs-name">Item</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Item</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span> <span class="hljs-attr">item</span>=<span class="hljs-string">{item}</span> <span class="hljs-attr">todos</span>=<span class="hljs-string">{todos}</span> <span class="hljs-attr">setTodos</span>=<span class="hljs-string">{setTodos}</span> /&gt;</span>
        ))
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Seems lonely in here, what are you up to?<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">ol</span>&gt;</span></span>
  );
}
</code></pre>
<p>Now that we have access to the todo data in our <code>&lt;Item /&gt;</code> component, we can persist data to localStorage after marking todo as completed:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-keyword">const</span> completeTodo = <span class="hljs-function">() =&gt;</span> {
  setTodos(<span class="hljs-function">(<span class="hljs-params">prevTodos</span>) =&gt;</span>
    prevTodos.map(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span>
      todo.id === item.id ? { ...todo, <span class="hljs-attr">is_completed</span>: !todo.is_completed } : todo
    )
  );

  <span class="hljs-comment">// Update localStorage after marking todo as completed</span>
  <span class="hljs-keyword">const</span> updatedTodos = <span class="hljs-built_in">JSON</span>.stringify(todos);
  <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"todos"</span>, updatedTodos);
};
</code></pre>
<p>We also want to persist the data to localStorage after editing a todo:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-keyword">const</span> handleInpuSubmit = <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  event.preventDefault();

  <span class="hljs-comment">// Update localStorage after editing todo</span>
  <span class="hljs-keyword">const</span> updatedTodos = <span class="hljs-built_in">JSON</span>.stringify(todos);
  <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"todos"</span>, updatedTodos);
  setEditing(<span class="hljs-literal">false</span>);
};

<span class="hljs-keyword">const</span> handleInputBlur = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Update localStorage after editing todo</span>
  <span class="hljs-keyword">const</span> updatedTodos = <span class="hljs-built_in">JSON</span>.stringify(todos);
  <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"todos"</span>, updatedTodos);

  setEditing(<span class="hljs-literal">false</span>);
};
</code></pre>
<p>Lastly we want to also persist the data to localStorage after we delete a todo:</p>
<pre><code class="lang-js"><span class="hljs-comment">// src/components/TODOList.jsx</span>

<span class="hljs-keyword">const</span> handleDelete = <span class="hljs-function">() =&gt;</span> {
  setTodos(<span class="hljs-function">(<span class="hljs-params">prevTodos</span>) =&gt;</span> prevTodos.filter(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo.id !== item.id));
  <span class="hljs-comment">// Update localStorage after deleting todo</span>
  <span class="hljs-keyword">const</span> updatedTodos = <span class="hljs-built_in">JSON</span>.stringify(
    todos.filter(<span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo.id !== item.id)
  );
  <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"todos"</span>, updatedTodos);
};
</code></pre>
<p>And that’s all you need – pretty easy right? Now when we create new todos, they’ll be persisted in localStorage even after reloading our app.</p>
<h3 id="heading-how-to-read-the-todo-data-from-localstorage">How to Read the Todo Data from localStorage</h3>
<p>Even though we've successfully persisted our data to localStorage, our app data is still wiped when we reload our app or the browser. That's because we are not yet utilizing the data stored in localStorage.</p>
<p>To address this, when our app is mounted (loaded), we want to retrieve the data from localStorage and then pass it to our state.</p>
<p>In our src/app/page.js, we'll read the data from localStorage and store it in our todos state.</p>
<pre><code class="lang-jsx"><span class="hljs-comment">// src/app/page.js</span>

<span class="hljs-string">"use client"</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Form <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Form"</span>;
<span class="hljs-keyword">import</span> Header <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Header"</span>;
<span class="hljs-keyword">import</span> TODOHero <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TODOHero"</span>;
<span class="hljs-keyword">import</span> TODOList <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/TODOList"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [todos, setTodos] = React.useState([]);

  <span class="hljs-comment">// Retrieve data from localStorage when component mounts</span>
  React.useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> storedTodos = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"todos"</span>);
    <span class="hljs-keyword">if</span> (storedTodos) {
      setTodos(<span class="hljs-built_in">JSON</span>.parse(storedTodos));
    }
  }, []);

  <span class="hljs-keyword">const</span> todos_completed = todos.filter(
    <span class="hljs-function">(<span class="hljs-params">todo</span>) =&gt;</span> todo.is_completed == <span class="hljs-literal">true</span>
  ).length;
  <span class="hljs-keyword">const</span> total_todos = todos.length;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Header</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TODOHero</span> <span class="hljs-attr">todos_completed</span>=<span class="hljs-string">{todos_completed}</span> <span class="hljs-attr">total_todos</span>=<span class="hljs-string">{total_todos}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Form</span> <span class="hljs-attr">todos</span>=<span class="hljs-string">{todos}</span> <span class="hljs-attr">setTodos</span>=<span class="hljs-string">{setTodos}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TODOList</span> <span class="hljs-attr">todos</span>=<span class="hljs-string">{todos}</span> <span class="hljs-attr">setTodos</span>=<span class="hljs-string">{setTodos}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>The code inside the <code>useEffect()</code> hook we run once the component is mounted.</p>
<p>This is the part that reads the data from localStorage:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> storedTodos = <span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"todos"</span>);
</code></pre>
<p>Since the data stored in localStorage is a string, we have to convert it back to our array of objects before we can use it:</p>
<pre><code class="lang-js"><span class="hljs-built_in">JSON</span>.parse(storedTodos)
</code></pre>
<p>And that’s all you need to get it working. Now even when we reload the app, the data is persisted as you can see in this video:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/008u_QJZBAs" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-and-weve-done-it">And We’ve Done It.</h2>
<p>Congratulations! After a journey filled with coding and persistence, we've successfully built a simple yet functional todo app from scratch. The journey might have been long, but the result is worth it.</p>
<p>You can explore the entire source code of the app <a target="_blank" href="https://github.com/iamspruce/create-a-todo-app-with-React">here</a>. Feel free to dive into the code and see how it all comes together.</p>
<p>But wait, there's more! If you're eager to try out the app yourself, I have a hosted version available <a target="_blank" href="https://create-a-todo-app-with-react.vercel.app/">here</a>. Go ahead and give it a try to experience the app firsthand.</p>
<p>Thank you for joining me on this coding adventure. I hope you've gained valuable insights into building React apps and persisting data with localStorage.</p>
<p>If you have any questions, feel free to message on Twitter at <a target="_blank" href="https://twitter.com/sprucekhalifa">@sprucekhalifa</a>, and don't forget to follow me for more insights and updates. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn REST APIs by Building a JavaScript Project ]]>
                </title>
                <description>
                    <![CDATA[ So, you've been learning JavaScript. I bet you're loving it. You've learned the basics and you're starting to get the hang of it. So you might be wondering what to do next. Well, let me introduce you to REST APIs, a powerful tool that you are going t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-rest-apis-javascript-project/</link>
                <guid isPermaLink="false">66d461663bc3ab877dae2251</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Mon, 11 Dec 2023 15:18:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/12/desktop-preview-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>So, you've been learning JavaScript. I bet you're loving it. You've learned the basics and you're starting to get the hang of it. So you might be wondering what to do next.</p>
<p>Well, let me introduce you to REST APIs, a powerful tool that you are going to add to your arsenal.</p>
<p>In this article, we are going to learn about REST APIs, what they are, and how to use them as a JavaScript developer.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-who-is-this-article-for">Introduction and Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-getting-started-with-rest-apis">Getting Started with REST APIs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-make-requests-with-rest-apis">How to Make Requests with REST APIs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-understanding-http-methods">Understanding HTTP Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-handle-responses-from-the-rest-api">How to Handle Responses from the REST API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-practical-example-how-to-build-a-web-application-with-a-public-rest-api">Practical Example: How to Build a Web Application with a Public Rest API</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-who-is-this-article-for">Who is this article for?</h2>
<p>If you're new to the concept of REST APIs, or have heard about them but feel unsure about how they work, this article is tailor-made for you. It's designed for JavaScript developers who are eager to learn the ropes of working with REST APIs.</p>
<h2 id="heading-what-do-i-need-to-continue-with-this-article">What do I need to continue with this article?</h2>
<p>To get the most out of this article, you need some basic knowledge of JavaScript, a browser, and a code editor. Sounds good?</p>
<h2 id="heading-what-will-i-learn-by-the-end-of-this-article">What will I learn by the end of this article?</h2>
<p>By the end of this article, you'll become acquainted with REST APIs. You'll learn how to make your first API request and handle the responses. You'll also build an IP Address Tracker application to put your skills into practice.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/12/desktop-preview.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Ip Address Tracker Application</em></p>
<h2 id="heading-getting-started-with-rest-apis">Getting Started with REST APIs</h2>
<p>Before we dive into the world of REST APIs, let's take a step back and understand what an API is.</p>
<h3 id="heading-what-is-an-api">What is an API?</h3>
<p>API stands for Application Programming Interface. It acts as a communication channel between two applications, such as a web form submitting data to a database.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727423426199/ecb2d72f-b8d0-4821-8040-6cd1b0d507e6.png" alt="ecb2d72f-b8d0-4821-8040-6cd1b0d507e6" class="image--center mx-auto" width="2000" height="770" loading="lazy"></p>
<p><em>Diagram showing how an API helps two applications communicate by requesting and sending data.</em></p>
<p>From the above image, you can see that the API acts as a bridge between the web form and the database. The API handles the <strong>request</strong> made from the web form and sends a <strong>response</strong> back to the web form. In simple terms, that is how APIs work.</p>
<h3 id="heading-what-is-a-rest-api">What is a REST API?</h3>
<p>Now that you know what an API is and how they work, what is REST? REST (Representational State Transfer) is a set of rules (well, you can call them guidelines) that define methods and protocols for how data should be sent, received, and stored.</p>
<p>So basically, REST is a type of API that follows a set of rules that make communication between two applications smooth and organized.</p>
<p>We are not going to go into details about the rules of REST APIs. Here, we just want to know how to use them for now.</p>
<p>There are only two operations that happen when it comes to using APIs: making <strong>a request</strong> and <strong>receiving a response.</strong> We are going to focus on these two operations as we go forward.</p>
<h2 id="heading-how-to-make-requests-with-rest-apis">How to Make Requests with Rest APIs</h2>
<p>REST APIs are typically exposed as an Endpoint, a URL that directs your request. For example, there's a REST API called <code>jsonplaceholder</code> providing random user data. The endpoint to get user data looks like this: https://jsonplaceholder.typicode.com/users.</p>
<p>To get the user data, you make a request to that endpoint using JavaScript's Fetch API:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> request = fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>);
<span class="hljs-built_in">console</span>.log(request.json());
</code></pre>
<p>Run the code above to see it in action. You might wonder why you're getting a Promise instead of the data. That's because the Fetch API returns a Promise, and you need to instruct your code to wait for the API response before finishing.</p>
<p>But how do you do that? You can use <code>async/await</code> method in JavaScript like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint);
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>Or you can use the <code>.then()</code> method:</p>
<pre><code class="lang-javascript">fetch(<span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>)
  .then(<span class="hljs-function">(<span class="hljs-params">response</span>) =&gt;</span> response.json())
  .then(<span class="hljs-function">(<span class="hljs-params">json</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(json));
</code></pre>
<p>Any of the above would do just fine. If you are not familiar with this code, I wrote a <a target="_blank" href="https://www.freecodecamp.org/news/javascript-promises-for-beginners/">beginner's guide to Promises in JavaScript</a> you can check it out.</p>
<p>Hey, now you know how to make a request and <code>GET</code> data from a REST API. But what if you want to add some data to some database using an API? How would you do that?</p>
<p>Well, we still have to use the fetch API, but this time we have to specify the method to be used. We'll take a look at those methods next.</p>
<h2 id="heading-understanding-http-methods">Understanding HTTP Methods</h2>
<p>In addition to the minimal syntax we've seen, the Fetch API takes in some options, and one of those options is the HTTP method.</p>
<p>HTTP methods inform the REST API about the type of request you're making. The common types are POST, GET, PUT, and DELETE, collectively known as CRUD operations (Create, Read, Update, Delete).</p>
<p>Let's look at each HTTP method separately.</p>
<h3 id="heading-get-http-method">GET HTTP Method</h3>
<p>This HTTP method is used to read data from the server when using the REST API. To add a method to the Fetch API, you specify it after the endpoint, like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, { <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span> });
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>When using the Fetch API, it's optional to specify the GET HTTP method. If you don't specify any HTTP method, the Fetch API assumes you're making a GET request. That's why the code you used for your first API request still works fine even without the HTTP method.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint);
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<h3 id="heading-post-http-method">POST HTTP Method</h3>
<p>Unlike the <code>GET</code> HTTP method, which retrieves data from an API, the POST HTTP method is used to add data when using REST APIs.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AddData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(data),
  });

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

<span class="hljs-keyword">const</span> data = { <span class="hljs-attr">username</span>: <span class="hljs-string">'John Snow'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">22</span> };

AddData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>If you want to add data to the Rest API using this method, you have to specify the <code>POST</code> HTTP method. You can also see that we passed the data we are trying to add to the <code>body</code> option.</p>
<p>Aside from HTTP methods, the Fetch API also has the <code>body</code> option that we can pass our data when adding data to our API. This data we are trying to add is usually in JSON format, which is why we have to convert our <code>Object</code> to JSON using the <code>JSON.stringify()</code> method.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> data = { <span class="hljs-attr">username</span>: <span class="hljs-string">'John Snow'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">22</span> };
<span class="hljs-keyword">const</span> json = <span class="hljs-built_in">JSON</span>.stringify(data);
<span class="hljs-built_in">console</span>.log(json);
</code></pre>
<h3 id="heading-put-http-method">PUT HTTP Method</h3>
<p>This method is used to update data when working with REST APIs. You use this method along with the data you want to update, just like the POST HTTP method.</p>
<p>Let's update the user with the <code>id</code> 11 we created above.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UpdateData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users/2'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'PUT'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(data),
  });

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

<span class="hljs-keyword">const</span> data = { <span class="hljs-attr">age</span>: <span class="hljs-number">42</span> }; <span class="hljs-comment">// update the age</span>

UpdateData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<h3 id="heading-delete-http-method">DELETE HTTP Method</h3>
<p>This method, as the name implies, is used to delete data permanently from a server when using REST APIs. You don't pass any data to the body when using this method. Let's delete the user we created above:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UpdateData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users/2'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, { <span class="hljs-attr">method</span>: <span class="hljs-string">'DELETE'</span> });

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

UpdateData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>Having learned all this, you can now confidently create, read, update, and delete data from the server by using REST APIs.</p>
<p>Now, when making requests to a REST API, the HTTP method and the body options are not the only things you can specify along with your request. You can also pass along <code>headers</code> with your request.</p>
<p>Headers allow you to provide additional information about the request you are making. For example, we can tell the REST API the type of content we are sending beforehand.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AddData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify(data),
    <span class="hljs-attr">headers</span>: { <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span> },
  });

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();
  <span class="hljs-built_in">console</span>.log(response);
}

<span class="hljs-keyword">const</span> data = { <span class="hljs-attr">username</span>: <span class="hljs-string">'John Snow'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">22</span> };

AddData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>The<code>headers: { "Content-Type": "application/json"}</code> header simply tells the REST API beforehand that we are trying to add data that is in JSON format. Of course, this is completely optional.</p>
<p>Up until now, we have only looked at making requests. lets now look at handling requests from a REST API</p>
<h2 id="heading-how-to-handle-responses-from-the-rest-api">How to Handle Responses from the Rest API</h2>
<p>Any time you make a request to an API, you will always get a response. There are a couple types of responses you can get back from a Rest API call. You either get a 2XX success response or a 4XX/5XX error response. In your JavaScript code, you'll need to handle these responses accordingly.</p>
<p>Don't worry – we're going to break down what the above responses mean.</p>
<h3 id="heading-understanding-response-codes">Understanding Response codes</h3>
<p>As stated above, anytime you make a request, you will always get a response. Depending on the status of your response code, you can determine if a response was successful or not.</p>
<h4 id="heading-2xx-success-status-code">2XX Success Status Code</h4>
<p>Success responses are usually in the range of 200 to 299 HTTP status codes. The most common success code is 200 OK, indicating that the request was successful. When you receive a successful response, you can handle the data returned by the API.</p>
<p>Here's an example of that shows the status code of our response:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, { <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span> });
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-built_in">console</span>.log(response.status);
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>If you get a <code>200</code> status code, it means that the request was successful and OK.</p>
<p>We should always use this status code to check if our request was successful before we try to use the data returned from an API request.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, { <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span> });
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-keyword">if</span> (request.status == <span class="hljs-number">200</span>) {
    <span class="hljs-comment">// Request was successful</span>
    <span class="hljs-built_in">console</span>.log(request.status);
  }
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>Additionally, you can also use the<code>Response.ok</code> property to check if the request was successful; this property will return <code>true</code> if the request was successful.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, { <span class="hljs-attr">method</span>: <span class="hljs-string">'GET'</span> });
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-keyword">if</span> (response.ok) {
    <span class="hljs-comment">// Request was successful</span>
    <span class="hljs-built_in">console</span>.log(response.status);
  }
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<h4 id="heading-4xx5xx-error-status-code">4XX/5XX Error Status Code</h4>
<p>When you make a request to an API, and you don't receive a success status code, you will either get a 400-499 or 500-599 error code. The error code you will receive will fall into one of these ranges.</p>
<p>Both of these status codes usually indicate an error. The 400–499 error codes indicate that there's something wrong with your request, while the 500–599 error codes indicate that error is coming from the server.</p>
<p>Consider the example below where we intentionally made a request to a non-existent endpoint (<a target="_blank" href="https://jsonplaceholder.typicode.com/nonexistent"><code>https://jsonplaceholder.typicode.com/nonexistent</code></a>) to trigger a <code>404 Not Found</code> error.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">AddData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/nonexistent'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>,
    <span class="hljs-attr">body</span>: data, <span class="hljs-comment">// don't convert the data to json</span>
  });

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-keyword">if</span> (response.ok) {
    <span class="hljs-built_in">console</span>.log(response);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`An error with status code <span class="hljs-subst">${response.status}</span> occured`</span>);
  }
}

<span class="hljs-keyword">const</span> data = { <span class="hljs-attr">username</span>: <span class="hljs-string">'John Snow'</span>, <span class="hljs-attr">age</span>: <span class="hljs-number">22</span> };

AddData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>The status code <code>404</code> we received here indicates that there's something wrong with our request.</p>
<p>I did not cover all the status codes here, but if you are looking for a comprehensive list of the status codes, you can take a look at this <a target="_blank" href="https://www.restapitutorial.com/httpstatuscodes.html">guide</a>.</p>
<p>Now depending on the response you receive, you can show different things to your users.</p>
<ul>
<li><p>if you receive a success status code, you can use the data to build your application as you deem fit</p>
</li>
<li><p>If you receive an error status code, you can show an Error message to your users as well</p>
</li>
</ul>
<h3 id="heading-how-to-handle-the-response-body">How to handle the response body</h3>
<p>Depending on the type of request you make, you are going to get back data as a response. To get this data we use the <code>request.json();</code>. We have used this a couple of times already – it will get the request body and parse the data back to an object that we can use.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint);

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json(); <span class="hljs-comment">// parse the data</span>

  <span class="hljs-built_in">console</span>.log(response);
}

GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>You don't need to do anything else in order to process the data returned from your API request.</p>
<p>Aside from the request body, you also get the <code>headers</code> along with the response. This can be useful if, for example, you want to check the type of data returned by your API request beforehand:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">let</span> endpoint = <span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(endpoint);

  <span class="hljs-keyword">const</span> dataType = request.headers.get(<span class="hljs-string">'content-type'</span>);

  <span class="hljs-keyword">if</span> (dataType.includes(<span class="hljs-string">'application/json'</span>)) {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json(); <span class="hljs-comment">// parse the data</span>
    <span class="hljs-built_in">console</span>.log(response);
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'We expected the data to be in json format'</span>);
  }
}
GetData(); <span class="hljs-comment">// call the function</span>
</code></pre>
<p>Well, enough of all the talk. Let's roll up our sleeves and try a practical example.</p>
<h2 id="heading-practical-example-how-to-build-a-web-application-with-a-public-rest-api">Practical Example: How to Build a Web Application with a Public Rest API</h2>
<p>I feel like we have learned a lot already, so let's put our new Rest API skills into practice, shall we?</p>
<p>Our task is to build a web application with an IP address API. It'll retrieve information about an IP address and display the location of the IP address on a map with some other information. This is what it is supposed to look like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727424349562/2f32e4cf-908f-411b-8eea-89e97984b18a.jpeg" alt="2f32e4cf-908f-411b-8eea-89e97984b18a" class="image--center mx-auto" width="1440" height="800" loading="lazy"></p>
<p><em>Application we'll build</em></p>
<p>To build this we are going to use:</p>
<ul>
<li><p><a target="_blank" href="https://geo.ipify.org/">IP Geolocation API by IPify</a> to get the IP address locations.</p>
</li>
<li><p>The endpoint for the API: <a target="_blank" href="https://geo.ipify.org/api/v2/country,city?apiKey=XXXXXXXX&amp;ipAddress=XXXXXXX"><code>https://geo.ipify.org/api/v2/country,city?apiKey=XXXXXXXX&amp;ipAddress=XXXXXXX</code></a></p>
</li>
<li><p>To get the API key you have to sign up for an account with <a target="_blank" href="https://geo.ipify.org/">IPify</a></p>
</li>
<li><p>To generate the map, we are going to be using <a target="_blank" href="https://leafletjs.com/">LeafletJS</a></p>
</li>
</ul>
<p>Now that we have that out of the way, let's build the HTML and CSS of the web application. If you are confident about your HTML and CSS skills, try building the web page on your own. Here's my implementation:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/GRzzeNp" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>Now that we have the HTML and CSS out of the way, the first thing we need to do is to get the IP address the user entered. So create a <code>index.js</code> file and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Select form */</span>
<span class="hljs-keyword">const</span> search_form = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.header_form'</span>);

search_form.addEventListener(<span class="hljs-string">'submit'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">/* stop form from auto submiting on click */</span>
  event.preventDefault();

  <span class="hljs-comment">/* get the value of the form field */</span>
  <span class="hljs-keyword">const</span> value = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'#search'</span>).value;

  <span class="hljs-built_in">console</span>.log(value);
});
</code></pre>
<p>Submit the the form to see the value that you entered in the HTML input form.</p>
<p>Next we need to pass that value into a function <code>search_Ip_Address()</code>. It actually makes a GET request to fetch our location data and uses the data to update the UI of our web application:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Select form */</span>
<span class="hljs-keyword">const</span> search_form = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.header_form'</span>);

search_form.addEventListener(<span class="hljs-string">'submit'</span>, <span class="hljs-function">(<span class="hljs-params">event</span>) =&gt;</span> {
  <span class="hljs-comment">/* stop form from auto submiting on click */</span>
  event.preventDefault();

  <span class="hljs-comment">/* get the value of the form field */</span>
  <span class="hljs-keyword">const</span> value = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'#search'</span>).value;

  <span class="hljs-comment">/* Pass the Ip address to the search_Ip_Address() function */</span>
  search_Ip_Address(value);
});

<span class="hljs-comment">/* Search for an IpAddress */</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search_Ip_Address</span>(<span class="hljs-params">ip_address</span>) </span>{
  <span class="hljs-keyword">const</span> api_key = <span class="hljs-string">'xxxxxxxxxxxxxxxxxxxxxxx'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(
    <span class="hljs-string">`https://geo.ipify.org/api/v2/country,city?apiKey=<span class="hljs-subst">${api_key}</span>&amp;ipAddress=<span class="hljs-subst">${ip_address}</span>`</span>,
  );
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-comment">/* Update the UI on the page */</span>
  <span class="hljs-keyword">const</span> { location, ip, isp } = response;
  update_ui(ip, location.city, location.timezone, isp);
}

<span class="hljs-comment">/* update UI function */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">update_ui</span>(<span class="hljs-params">ip_address, location, timezone, isp</span>) </span>{
  <span class="hljs-comment">/* select all the elements on the page */</span>
  <span class="hljs-keyword">const</span> address = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.address'</span>);
  <span class="hljs-keyword">const</span> city = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.location'</span>);
  <span class="hljs-keyword">const</span> utc = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.utc'</span>);
  <span class="hljs-keyword">const</span> isprovider = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.isp'</span>);

  <span class="hljs-comment">/* Update all the elements on the page */</span>
  address.textContent = ip_address;
  city.textContent = location;
  utc.textContent = <span class="hljs-string">'UTC'</span> + timezone;
  isprovider.textContent = isp;
}
</code></pre>
<p>Next we need to create our map. To begin, add the following to the <code>head</code> section of your HTML file:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  ...
  <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
    <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>
    <span class="hljs-attr">href</span>=<span class="hljs-string">"https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"</span>
    <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="</span>
    <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">""</span>
  /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">script</span>
    <span class="hljs-attr">src</span>=<span class="hljs-string">"https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"</span>
    <span class="hljs-attr">integrity</span>=<span class="hljs-string">"sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="</span>
    <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">""</span>
  &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  ...
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
</code></pre>
<p>Also make sure you have a div element on the page with an <code>id</code> of map:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"map"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"map"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>Next we need to create a function that will create the map for us. So in your <code>script.js</code> add the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* create the map */</span>
<span class="hljs-keyword">let</span> map;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">create_map</span>(<span class="hljs-params">lat, lng</span>) </span>{
  map = L.map(<span class="hljs-string">'map'</span>).setView([lat, lng, country, region], <span class="hljs-number">14</span>);
  L.tileLayer(<span class="hljs-string">'https://tile.openstreetmap.org/{z}/{x}/{y}.png'</span>, {
    <span class="hljs-attr">maxZoom</span>: <span class="hljs-number">20</span>,
    <span class="hljs-attr">attribution</span>:
      <span class="hljs-string">'&amp;copy; &lt;a href="http://www.openstreetmap.org/copyright"&gt;OpenStreetMap&lt;/a&gt;'</span>,
  }).addTo(map);

  L.marker([lat, lng])
    .addTo(map)
    .bindPopup(<span class="hljs-string">`<span class="hljs-subst">${region}</span>, <span class="hljs-subst">${country}</span>`</span>)
    .openPopup();
}
</code></pre>
<p>Lastly we just need to call the <code>create_map()</code> function any time the user searches for an IP address.</p>
<p>To call the <code>create_map()</code> when the user searches for an Ip address, update the <code>search_Ip_Address()</code> function:</p>
<pre><code class="lang-js"><span class="hljs-comment">/* Search for an IpAddress */</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search_Ip_Address</span>(<span class="hljs-params">ip_address</span>) </span>{
  <span class="hljs-keyword">const</span> api_key = <span class="hljs-string">'at_HhKzCe09UZIYJC9pY7YTg7kMMUzZd'</span>;
  <span class="hljs-keyword">const</span> request = <span class="hljs-keyword">await</span> fetch(
    <span class="hljs-string">`https://geo.ipify.org/api/v2/country,city?apiKey=<span class="hljs-subst">${api_key}</span>&amp;ipAddress=<span class="hljs-subst">${ip_address}</span>`</span>,
  );
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> request.json();

  <span class="hljs-keyword">const</span> { location, ip, isp } = response;

  <span class="hljs-comment">/* Update the ui on the page */</span>
  update_ui(ip, location.city, location.timezone, isp);

  <span class="hljs-comment">/* Update the map on the page */</span>
  <span class="hljs-comment">/* first remove all map instances if any */</span>
  <span class="hljs-keyword">if</span> (map !== <span class="hljs-literal">undefined</span> &amp;&amp; map !== <span class="hljs-literal">null</span>) {
    map.remove();
  }
  create_map(location.lat, location.lng, location.country, location.region);
}
</code></pre>
<p>Lastly, just call the <code>search_Ip_Address()</code> function when the page finishes loading:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> defaultIp = <span class="hljs-string">'197.210.78.172'</span>;
search_Ip_Address(defaultIp);
</code></pre>
<p>And there you go – a nice IP tracker web application. I hope that building this application helped you reinforce your newfound REST API skills.</p>
<p>To provide you with an opportunity for practice, here's a challenge you can undertake. Below is the final preview of the web app:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/rNPPoag" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h3 id="heading-challenge">Challenge:</h3>
<p>Currently, our IP tracker application lacks error handling. For instance, if a user enters a random word in the search input field that is not a valid IP address, the entire application will break.</p>
<p>As conscientious developers, we should always be vigilant about errors and handle them gracefully. Therefore, your challenge is twofold:</p>
<ol>
<li><p>Implement input validation to ensure that the entered value is always a valid IP address. If the user enters an invalid IP address, display an error message.</p>
</li>
<li><p>Handle all unforeseen errors that users may encounter during the application's usage.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Knowing how to work with REST APIs is a key skill that developers must have. In this article, you learned about REST APIs and how to use them to develop your own applications.</p>
<p>If you have any questions, feel free to message me on Twitter at <a target="_blank" href="https://twitter.com/sprucekhalifa">@sprucekhalifa</a>, and don't forget to follow me for more insights and updates. Happy coding!</p>
<p>The example used in this tutorial was gotten from <a target="_blank" href="http://frontendmentor.io">frontendmentor.io</a> <a target="_blank" href="https://www.frontendmentor.io/challenges/ip-address-tracker-I8-0yYAH0">IP address tracker challenge on Frontend Mentor</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Successful Projects as a Junior Developer ]]>
                </title>
                <description>
                    <![CDATA[ Several months ago, I stumbled upon a coding challenge that intrigued me. Here's what it was: https://twitter.com/hussien_coding/status/1576929379736727554   The task was seemingly simple: build six squares with no color, make each square turn green ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-projects-as-a-junior-developer/</link>
                <guid isPermaLink="false">66d461587df3a1f32ee7f8b0</guid>
                
                    <category>
                        <![CDATA[ Junior developer  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Tue, 21 Nov 2023 21:25:28 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/scott-graham-5fNmWej4tAA-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Several months ago, I stumbled upon a coding challenge that intrigued me. Here's what it was:</p>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/hussien_coding/status/1576929379736727554"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<p> </p>
<p>The task was seemingly simple: build six squares with no color, make each square turn green when clicked. Then when the last square turned green, make them all go back to no color in the reverse order in which they were clicked.</p>
<p>I was excited to test out the skills of some junior developers I was working with who were just starting out in tech, so I shared the challenge with them. But the results were not what I expected.</p>
<p>Despite its apparent simplicity, the challenge brought out varying results. Some students successfully created a functional solution, while others struggled with the required programming concepts.</p>
<p>That's when I realized that this could be a great opportunity for a lot of people. So if you're a junior developer finding it challenging to create your own portfolio/demo projects, fear not! This article will guide you through the process of successfully building a project with a straightforward approach.</p>
<h2 id="heading-who-is-this-article-for">Who is This Article For?</h2>
<p>This article is specifically tailored for junior developers who might be struggling to create their own personal side projects.</p>
<p>If you often find yourself relying on tutorials or feel like you lack the creativity to create projects independently, then this article is for you.</p>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Let's take a look at the challenge I sent the students:</p>
<pre><code class="lang-plaintext">Build six squares with no color 
Every time you click one, it turns green 
When the last square turns green, they all go back to no color in backwards sequence to which it was clicked (not all at once)
</code></pre>
<p>If you were one of the students presented with this challenge, what would you do first? While it may be tempting to dive right into coding, it's important to recognize that <strong>writing code</strong> is actually the <strong>last step</strong> of building a project.</p>
<p>So, what's the first step? The first step is to <strong>think</strong>. Yeah I mean to literally stop and think about the problem you're trying to solve.</p>
<h2 id="heading-how-to-think-about-the-problem">How to Think About the Problem</h2>
<p>When approaching a project, it's important to think of it as a problem that needs a solution. Take your time to carefully consider the problem, and then break it down into smaller parts.</p>
<p>To do this, you may find it helpful to step away from your computer and grab a pencil and piece of paper.</p>
<p>For example, when faced with any kind of challenge, you can start by breaking the project down into more manageable parts. This might include:</p>
<ol>
<li><p>Creating the six squares</p>
</li>
<li><p>Determining a way to change their color when clicked</p>
</li>
<li><p>Create a mechanism to track which squares have been clicked</p>
</li>
<li><p>Devise a method for the squares to return to their original state in the reverse order they were clicked</p>
</li>
</ol>
<p>No matter how big a project may seem, it's always important to break it down into smaller parts. This makes it easier to tackle each individual piece one at a time while staying organized and focused.</p>
<p>So, when faced with a large project, don't be intimidated. Instead, take the time to break it down into smaller pieces and focus on tackling each piece individually. By doing so, you'll be able to stay organized, stay focused, and ultimately be more successful in your project.</p>
<p>After taking some time to carefully consider the challenge, I was able to come up with a potential solution. Here's what I came up with:</p>
<pre><code class="lang-plaintext">// step 1: creating the six squares

- CREATE six individual buttons in HTML 
- GIVE each button a class name of square
- GIVE them unique IDs

// step 2: Determining a way to change their color when clicked

- ADD a CLICK Event Listener to each button
- CALL a function called UpdateSquares() that changes the color of a clicked button

// step 3: Create a mechanism to track which squares have been clicked

- CREATE an array called `array_sqr` that stores the unique ID of a clicked button
- When a button has been clicked, add the ID to the array

// step 4: devise a method for the squares to return to their original state in the reverse order they were clicked

- When `array_sqr.length == 6` call a function called ReverseSquares()
- In the ReverseSquares() function, loop through `array_sqr`
- Inside the loop, SELECT each button with the unique IDs in `array_sqr`
- REMOVE the color green from the selected button
</code></pre>
<p>After you have carefully thought about your project, you can now move on to the next step, which is actually building your project.</p>
<h2 id="heading-how-to-solve-the-problem-and-build-the-solution">How to Solve the Problem and Build the Solution</h2>
<p>After careful consideration of the challenge, it's time to move on to building the project. Let's go through the steps:</p>
<h3 id="heading-step-1-create-the-six-squares">Step 1: Create the Six Squares</h3>
<p>In this step, we have three things to do: create six individual buttons in HTML, give each button the class name of a square, and give them unique IDs.</p>
<p>You can do that in HTML like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"1"</span>&gt;</span>
            Button 1
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"2"</span>&gt;</span>
            Button 2
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"3"</span>&gt;</span>
            Button 3
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"4"</span>&gt;</span>
            Button 4
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"5"</span>&gt;</span>
            Button 5
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"square"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"6"</span>&gt;</span>
            Button 6
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"script.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Above, we just created the buttons with unique IDs just like we wrote down.</p>
<h3 id="heading-step-2-determine-a-way-to-change-their-color-when-clicked">Step 2: Determine a way to change their color when clicked.</h3>
<p>In this step, we just have two tasks: ADD a CLICK Event Listener to each button, and then call a function called <code>UpdateSquares()</code> that changes the color of a clicked button.</p>
<p>We will do this in JavaScript, so we'll create a new file called <code>script.js</code> with the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> buttons = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">".square"</span>);

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> button <span class="hljs-keyword">of</span> buttons) {
    button.addEventListener(<span class="hljs-string">"click"</span>, UpdateSquares);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UpdateSquares</span>(<span class="hljs-params">event</span>) </span>{
    <span class="hljs-keyword">const</span> btn = event.target;
    btn.style.backgroundColor = <span class="hljs-string">'green'</span>;
    array_sqr.push(btn.id);
}
</code></pre>
<h3 id="heading-step-3-create-a-mechanism-to-track-which-squares-have-been-clicked">Step 3: Create a mechanism to track which squares have been clicked.</h3>
<p>In the next step we need to create an empty array called <code>array_sqr</code> that stores the unique ID of a clicked button. Then, when a button has been clicked, we need to add the ID to the array. Modifying our code to achieve the above, we have this:</p>
<pre><code class="lang-js">…
<span class="hljs-keyword">let</span> array_sqr = []; <span class="hljs-comment">// create the empty array</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UpdateSquares</span>(<span class="hljs-params">event</span>) </span>{
    <span class="hljs-keyword">const</span> btn = event.target;
    btn.style.backgroundColor = <span class="hljs-string">'green'</span>;
    array_sqr.push(btn.id); <span class="hljs-comment">// push the ID to the array</span>
}
</code></pre>
<p>In the above code, all we have done is keep track of the way the buttons are clicked by storing them in an array.</p>
<h3 id="heading-step-4-devise-a-method-for-the-squares-to-return-to-their-original-state-in-the-reverse-order-they-were-clicked">Step 4: Devise a method for the squares to return to their original state in the reverse order they were clicked.</h3>
<p>In this last step, we have to call a function ReverseSquares() when <code>array_sqr.length == 6</code>.</p>
<p>In the <code>ReverseSquares()</code> function, loop through <code>array_sqr</code>. Inside the loop, select each button with the unique IDs in <code>array_sqr</code> and remove the color green from the selected button.</p>
<p>Below is the code to do this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> buttons = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">".square"</span>);

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> button <span class="hljs-keyword">of</span> buttons) {
    button.addEventListener(<span class="hljs-string">"click"</span>, UpdateSquares);
}

<span class="hljs-keyword">let</span> array_sqr = [];

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UpdateSquares</span>(<span class="hljs-params">event</span>) </span>{
    <span class="hljs-keyword">const</span> btn = event.target;
    btn.style.backgroundColor = <span class="hljs-string">'green'</span>;
    array_sqr.push(btn.id);

    <span class="hljs-keyword">if</span> (array_sqr.length == <span class="hljs-number">6</span>) {
        ReverseSquares();
    }
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ReverseSquares</span>(<span class="hljs-params"></span>) </span>{
    array_sqr.reverse();

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> id <span class="hljs-keyword">of</span> array_sqr) {
        <span class="hljs-keyword">const</span> reverse_btn = <span class="hljs-built_in">document</span>.getElementById(id);

        <span class="hljs-comment">// Remove the color </span>
        reverse_btn.style.backgroundColor = <span class="hljs-string">'white'</span>;

        <span class="hljs-comment">/* Also clear the array */</span>
        array_sqr = [];
    }
}
</code></pre>
<p>With the code above, we are practically done with the project, and it works as expected-ish. Take a look at the demo below:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/PoVReva" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>The only thing left to figure out is that at the moment, all the colors are removed at the same time. So we need to solve this, which will lead us to the final aspect of building our project.</p>
<h2 id="heading-how-to-improve-the-solution">How to Improve the Solution</h2>
<p>Our project currently has a problem where the color is removed from all the squares at the same time. So we need to fix that.</p>
<p>Every project has to undergo this crucial step of making updates and fixes. It's very hard to build a perfect project on your first try. I didn't even build the demo in this tutorial on my first try.</p>
<p>Improving your project can sometimes be even tougher than building the project itself. Fun fact: it took me more time to get the colors to change at different intervals than actually writing the code for the demo I used in this tutorial.</p>
<p>This steps generally involves a lot of Googling and sometimes even asking others for help. It’s perfectly okay to do that – it doesn't make you a bad developer.</p>
<p>Now that we have got that out of the way, let's improve our project. All we have to do is modify the <code>ReverseSquares()</code> function like so:</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ReverseSquares</span>(<span class="hljs-params"></span>) </span>{
    array_sqr.reverse();
    <span class="hljs-comment">// Use for..of loop to apply different timeouts for each button</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> [index, id] <span class="hljs-keyword">of</span> array_sqr.entries()) {
        <span class="hljs-keyword">const</span> reverse_btn = <span class="hljs-built_in">document</span>.getElementById(id);

        <span class="hljs-comment">// Remove the color after a delay, with increasing delay for each button</span>
        <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
            reverse_btn.style.backgroundColor = <span class="hljs-string">'white'</span>;
        }, index * <span class="hljs-number">1000</span>);

        <span class="hljs-comment">/* Also clear the array */</span>
        array_sqr = [];
    }
}
</code></pre>
<p>When everything is put together, you have a solution that works. It might not be perfect, but it works – and that's a win.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/qBgoYer" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-summary">Summary</h2>
<p>Creating side projects as a junior developer might seem challenging. But by following a systematic approach of thinking things through, planning out your code, actually coding, and then improving on your solution, you can successfully build projects that showcase your skills and creativity.</p>
<p>Don't be afraid to break down larger projects into smaller, more manageable parts. And remember that improvement is an integral part of the development process.</p>
<p>If you have any questions, feel free to message on Twitter at <a target="_blank" href="https://twitter.com/sprucekhalifa">@sprucekhalifa</a>, and don't forget to follow me for more insights and updates. Happy coding!</p>
<p>Photo by <a target="_blank" href="https://unsplash.com/@homajob?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Scott Graham</a> on <a target="_blank" href="https://unsplash.com/photos/person-holding-pencil-near-laptop-computer-5fNmWej4tAA?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Full Stack App with Next.js 13 and Firebase ]]>
                </title>
                <description>
                    <![CDATA[ Next.js is a React framework that makes building powerful full stack (front end + back end) applications a lot easier. The team behind Next.js recently released Next.js 13 which has a whole lot of futures like a new app Directory, server and client c... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-full-stack-app-with-nextjs13-and-firebase/</link>
                <guid isPermaLink="false">66d4614e230dff0166905883</guid>
                
                    <category>
                        <![CDATA[ Firebase ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Fri, 17 Feb 2023 17:38:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/pexels-sevenstorm-juhaszimrus-443383--1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Next.js is a React framework that makes building powerful full stack (front end + back end) applications a lot easier.</p>
<p>The team behind Next.js <a target="_blank" href="https://nextjs.org/blog/next-13">recently released Next.js 13</a> which has a whole lot of futures like a new <code>app</code> Directory, server and client components, and more.</p>
<p>In this article, you'll learn how to use the new Next.js 13 and Firebase database to build a full stack application.</p>
<p>Before you continue, this article assumes you have a basic knowledge of JavaScript, React, and Next.js. If you need to brush up on those skills, here are some beginner-friendly resources:</p>
<ul>
<li><p><a target="_blank" href="https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/">Learn JavaScript – curriculum</a> and <a target="_blank" href="https://www.freecodecamp.org/news/learn-javascript-interactive-course/">interactive course</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/learn-react-js-in-this-free-7-hour-course/">Learn React - full course</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/the-next-js-handbook/">Learn Next.js - full handbook</a></p>
</li>
</ul>
<p>Now if you're ready, let's dive in.</p>
<h2 id="heading-how-to-set-up-a-nextjs-13-project">How to Set Up a Next.js 13 Project</h2>
<p>To set up Next.js, you need to have Node.js and npm/yarn installed on your computer. If you dont have them, you can install them from their official websites: <a target="_blank" href="https://nodejs.org/en/">Node.js website</a> and <a target="_blank" href="https://www.npmjs.com/">npm website</a> (but npm is included when you install Node).</p>
<ol>
<li><p>In your desired directory, launch your terminal and run the following <code>npx create-next-app@latest --experimental-app</code>.</p>
</li>
<li><p>Enter your project name and click enter and wait for it to install.</p>
</li>
<li><p>A new directory with your project name will be created with the necessary files.</p>
</li>
<li><p>cd your way into the new directory: <code>cd my-project-name</code></p>
</li>
<li><p>To start the development server, run the following command:</p>
<pre><code class="lang-plaintext"> // if you're using yarn
 yarn run dev

 // if you're using npm
 npm run dev
</code></pre>
</li>
<li><p>Running that command will start the developement server and you can see your Next.js 13 app running on http://localhost:3000.</p>
</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot-2023-02-15-at-5.33.52-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Next.js 13 app</em></p>
<h3 id="heading-how-to-set-up-firebase-in-nextjs">How to Set Up Firebase in Next.js</h3>
<p>Firebase is a BaaS – Backend-as-a-Service – platform that provides cloud backend services such as authentication, realtime database, cloud storage, analytics and more.</p>
<p>In this tutorial we are going to be using Firebase as our database. Follow the steps below to create a Firebase app:</p>
<ol>
<li><p>Go to https://console.firebase.google.com/ and login in with your Google account.</p>
</li>
<li><p>Click on <strong>Add Project</strong> and give your project a name. Click on <strong>Continue</strong>.</p>
</li>
<li><p>On the next screen you can choose if you want to enable analytics for your project.</p>
</li>
<li><p>Click on <strong>Create project</strong>.</p>
</li>
<li><p>Next, you need to create a web app. On your project homepage click on the web icon to create your web app:</p>
<p> <img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot-2023-02-15-at-5.40.33-PM.png" alt="Screenshot-2023-02-15-at-5.40.33-PM" width="600" height="400" loading="lazy"></p>
</li>
<li><p>Give your web app a name and click <strong>Register app</strong>.</p>
<p> <img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot-2023-02-15-at-5.40.48-PM.png" alt="Screenshot-2023-02-15-at-5.40.48-PM" width="600" height="400" loading="lazy"></p>
</li>
<li><p>Copy the configuration file we are going to need it later. Click next until you are done.</p>
</li>
<li><p>On your project homepage again, <strong>choose a product to add to your app</strong>. For the sake of this tutorial, add only <strong>Authentication</strong> and <strong>Cloud Firestore</strong>.</p>
<p> <img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot-2023-02-15-at-6.33.34-PM.png" alt="Screenshot-2023-02-15-at-6.33.34-PM" width="600" height="400" loading="lazy"></p>
</li>
<li><p>For the Authentication choose <strong>Sign-in method</strong> add <strong>Email/password</strong>.</p>
</li>
</ol>
<p>Once you have successfully set up firebase we can now use it as a backend for your Next.js 13 app.</p>
<p>To use Firebase with Next.js, follow these steps:</p>
<ol>
<li><p>Install the latest firebase SDK on your Next.js project by running the following command on your terminal</p>
<pre><code class="lang-js"> yarn add firebase

 <span class="hljs-comment">// or if you are using npm</span>
 npm install firebase
</code></pre>
</li>
<li><p>Create a <code>.env</code> file in the root directory of your Next.js project and add your Firebase configuration files (the ones you copied earlier). It should look like this:</p>
<pre><code class="lang-js"> NEXT_PUBLIC_FIREBASE_API_KEY=api-key
 NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=auth-domain
 NEXT_PUBLIC_FIREBASE_PROJECT_ID=project-id
 NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=storage-bucket
 NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=sender-id
 NEXT_PUBLIC_FIREBASE_APP_ID=app-id
 NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=analytic-id
</code></pre>
</li>
<li><p>Next, to make things more tidy, in your <strong>src</strong> directory create a folder named <strong>firebase</strong> and create a file <code>config.js</code> with the following code:</p>
<pre><code class="lang-js"> <span class="hljs-comment">// Import the functions you need from the SDKs you need</span>
 <span class="hljs-keyword">import</span> { initializeApp, getApps } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/app"</span>;

 <span class="hljs-keyword">const</span> firebaseConfig = {
     <span class="hljs-attr">apiKey</span>: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
     <span class="hljs-attr">authDomain</span>: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
     <span class="hljs-attr">projectId</span>: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
     <span class="hljs-attr">storageBucket</span>: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
     <span class="hljs-attr">messagingSenderId</span>: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
     <span class="hljs-attr">appId</span>: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
     <span class="hljs-attr">measurementId</span>: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
 };

 <span class="hljs-comment">// Initialize Firebase</span>
 <span class="hljs-keyword">let</span> firebase_app = getApps().length === <span class="hljs-number">0</span> ? initializeApp(firebaseConfig) : getApps()[<span class="hljs-number">0</span>];

 <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> firebase_app;
</code></pre>
</li>
</ol>
<p>Now you are all set, you are now ready to use Firebase as a database in your Next.js 13 app.</p>
<h2 id="heading-how-to-set-up-authentication">How to Set Up Authentication</h2>
<p>When it comes to building full stack applications, the first thing that comes to mind is authentication. We need a way to signup and signin in users, and we can do this easily with Firebase.</p>
<p>In your <strong>src &gt; firebase</strong> directory, create a new directory called <strong>auth</strong>. We'll add all our firebase authentication related code in this directory.</p>
<p>Now create a <code>signup.js</code> file in the <strong>src &gt; firebase &gt; auth</strong> directory with the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> firebase_app <span class="hljs-keyword">from</span> <span class="hljs-string">"../config"</span>;
<span class="hljs-keyword">import</span> { createUserWithEmailAndPassword, getAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/auth"</span>;

<span class="hljs-keyword">const</span> auth = getAuth(firebase_app);


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">signUp</span>(<span class="hljs-params">email, password</span>) </span>{
    <span class="hljs-keyword">let</span> result = <span class="hljs-literal">null</span>,
        error = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">try</span> {
        result = <span class="hljs-keyword">await</span> createUserWithEmailAndPassword(auth, email, password);
    } <span class="hljs-keyword">catch</span> (e) {
        error = e;
    }

    <span class="hljs-keyword">return</span> { result, error };
}
</code></pre>
<p>Now let's break this down a bit. What we are doing here is exporting a <code>signUp()</code>function that uses the Firebase <strong>createUserWithEmailAndPassword()</strong> method to sign up new users. Now we can use this <code>signUp()</code> function anywhere in our app.</p>
<p>In the same directory, let's add our <code>signIn()</code> function. Create a <code>signin.js</code> file with the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> firebase_app <span class="hljs-keyword">from</span> <span class="hljs-string">"../config"</span>;
<span class="hljs-keyword">import</span> { signInWithEmailAndPassword, getAuth } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/auth"</span>;

<span class="hljs-keyword">const</span> auth = getAuth(firebase_app);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">signIn</span>(<span class="hljs-params">email, password</span>) </span>{
    <span class="hljs-keyword">let</span> result = <span class="hljs-literal">null</span>,
        error = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">try</span> {
        result = <span class="hljs-keyword">await</span> signInWithEmailAndPassword(auth, email, password);
    } <span class="hljs-keyword">catch</span> (e) {
        error = e;
    }

    <span class="hljs-keyword">return</span> { result, error };
}
</code></pre>
<h3 id="heading-how-to-create-the-signin-and-signup-pages-in-nextjs">How to Create the Signin and Signup pages in Next.js</h3>
<p>In Next.js 13 you create new pages in the <code>app</code> directory. Each page is a folder with a <code>page.js</code> file – you can learn more about creating <a target="_blank" href="https://beta.nextjs.org/docs/routing/pages-and-layouts">pages from the Next.js docs.</a></p>
<p>To create the sign up page, create a new <strong>signup &gt; page.js</strong> file in your <strong>app</strong> directory and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-string">'use client'</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> signUp <span class="hljs-keyword">from</span> <span class="hljs-string">"@/firebase/auth/signup"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/navigation'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [email, setEmail] = React.useState(<span class="hljs-string">''</span>)
    <span class="hljs-keyword">const</span> [password, setPassword] = React.useState(<span class="hljs-string">''</span>)
    <span class="hljs-keyword">const</span> router = useRouter()

    <span class="hljs-keyword">const</span> handleForm = <span class="hljs-keyword">async</span> (event) =&gt; {
        event.preventDefault()

        <span class="hljs-keyword">const</span> { result, error } = <span class="hljs-keyword">await</span> signUp(email, password);

        <span class="hljs-keyword">if</span> (error) {
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">console</span>.log(error)
        }

        <span class="hljs-comment">// else successful</span>
        <span class="hljs-built_in">console</span>.log(result)
        <span class="hljs-keyword">return</span> router.push(<span class="hljs-string">"/admin"</span>)
    }
    <span class="hljs-keyword">return</span> (<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-wrapper"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-60 mb-30"</span>&gt;</span>Sign up<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleForm}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEmail(e.target.value)} required type="email" name="email" id="email" placeholder="example@mail.com" /&gt;
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"password"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPassword(e.target.value)} required type="password" name="password" id="password" placeholder="password" /&gt;
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Sign up<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>);
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Page;<span class="hljs-string">`</span>
</code></pre>
<p>By default, each page you add in the <code>app</code> directory is a <a target="_blank" href="https://beta.nextjs.org/docs/rendering/server-and-client-components">Server component</a> which means we cannot add client-side interactivity like adding an <code>onSubmit()</code> to a form element. To add this client-side interactivity we tell Next.js that we want a Client component by adding the following at the top of the file before any imports:</p>
<pre><code class="lang-js"><span class="hljs-string">'use client'</span>

<span class="hljs-comment">// component code</span>
</code></pre>
<p>In the same manner, we can create our login page. To create the sign in page, create a new <strong>signin &gt; page.js</strong> file in your <strong>app</strong> directory and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-string">'use client'</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> signIn <span class="hljs-keyword">from</span> <span class="hljs-string">"@/firebase/auth/signin"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/navigation'</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [email, setEmail] = React.useState(<span class="hljs-string">''</span>)
    <span class="hljs-keyword">const</span> [password, setPassword] = React.useState(<span class="hljs-string">''</span>)
    <span class="hljs-keyword">const</span> router = useRouter()

    <span class="hljs-keyword">const</span> handleForm = <span class="hljs-keyword">async</span> (event) =&gt; {
        event.preventDefault()

        <span class="hljs-keyword">const</span> { result, error } = <span class="hljs-keyword">await</span> signIn(email, password);

        <span class="hljs-keyword">if</span> (error) {
            <span class="hljs-keyword">return</span> <span class="hljs-built_in">console</span>.log(error)
        }

        <span class="hljs-comment">// else successful</span>
        <span class="hljs-built_in">console</span>.log(result)
        <span class="hljs-keyword">return</span> router.push(<span class="hljs-string">"/admin"</span>)
    }
    <span class="hljs-keyword">return</span> (<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"wrapper"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form-wrapper"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-60 mb-30"</span>&gt;</span>Sign up<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{handleForm}</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"form"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEmail(e.target.value)} required type="email" name="email" id="email" placeholder="example@mail.com" /&gt;
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"password"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Password<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPassword(e.target.value)} required type="password" name="password" id="password" placeholder="password" /&gt;
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Sign up<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>);
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Page;
</code></pre>
<h3 id="heading-how-to-listen-for-authentication-changes">How to Listen for Authentication Changes</h3>
<p>Throughout our application we want to be able to tell if a certain user is logged in or not. We can create protected pages and only display some certain contents to the logged in user. Firebase provides us with an <code>onAuthStateChanged()</code> method that we can listen to for changes.</p>
<p>To make the user data from the above method available throughout our app, we are going to use React Context API. Create a folder named <strong>context</strong> in your <strong>src</strong> directory. Inside the <strong>context</strong> directory create a file called <code>AuthContext.js</code> and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> {
    onAuthStateChanged,
    getAuth,
} <span class="hljs-keyword">from</span> <span class="hljs-string">'firebase/auth'</span>;
<span class="hljs-keyword">import</span> firebase_app <span class="hljs-keyword">from</span> <span class="hljs-string">'@/firebase/config'</span>;

<span class="hljs-keyword">const</span> auth = getAuth(firebase_app);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> AuthContext = React.createContext({});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> useAuthContext = <span class="hljs-function">() =&gt;</span> React.useContext(AuthContext);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> AuthContextProvider = <span class="hljs-function">(<span class="hljs-params">{
    children,
}</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> [user, setUser] = React.useState(<span class="hljs-literal">null</span>);
    <span class="hljs-keyword">const</span> [loading, setLoading] = React.useState(<span class="hljs-literal">true</span>);

    React.useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> unsubscribe = onAuthStateChanged(auth, <span class="hljs-function">(<span class="hljs-params">user</span>) =&gt;</span> {
            <span class="hljs-keyword">if</span> (user) {
                setUser(user);
            } <span class="hljs-keyword">else</span> {
                setUser(<span class="hljs-literal">null</span>);
            }
            setLoading(<span class="hljs-literal">false</span>);
        });

        <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> unsubscribe();
    }, []);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AuthContext.Provider</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">user</span> }}&gt;</span>
            {loading ? <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> : children}
        <span class="hljs-tag">&lt;/<span class="hljs-name">AuthContext.Provider</span>&gt;</span></span>
    );
};
</code></pre>
<p>Above we are simply creating a Provider that returns the user object if the user is logged in. If the user is not logged in, we simply return <code>null</code>.</p>
<p>To be able to use the value passed to the <code>&lt;AuthContext.Provider&gt;</code> we are exporting <code>useAuthContext</code> from the file. With that we can use the <code>user</code> value.</p>
<p>Before we can use this context we need to wrap all our components with <code>AuthContextProvider</code>. Open the <strong>src &gt; app &gt; layout.js</strong> file and edit the code with the following:</p>
<pre><code class="lang-js"><span class="hljs-string">'use client'</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'./globals.css'</span>
<span class="hljs-keyword">import</span> { AuthContextProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">'@/context/AuthContext'</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">RootLayout</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
      {/*
        <span class="hljs-tag">&lt;<span class="hljs-name">head</span> /&gt;</span> will contain the components returned by the nearest parent
        head.js. Find out more at https://beta.nextjs.org/docs/api-reference/file-conventions/head
      */}
      <span class="hljs-tag">&lt;<span class="hljs-name">head</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">AuthContextProvider</span>&gt;</span>
          {children}
        <span class="hljs-tag">&lt;/<span class="hljs-name">AuthContextProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></span>
  )
}
</code></pre>
<p>Now we can create protected pages and display specific content to different users.</p>
<h3 id="heading-how-to-create-protected-pages">How to Create Protected Pages</h3>
<p>Create the directory <strong>admin &gt; page.js</strong> in your <code>app</code> directory and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-string">'use client'</span>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useAuthContext } <span class="hljs-keyword">from</span> <span class="hljs-string">"@/context/AuthContext"</span>;
<span class="hljs-keyword">import</span> { useRouter } <span class="hljs-keyword">from</span> <span class="hljs-string">"next/navigation"</span>;
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> { user } = useAuthContext()
    <span class="hljs-keyword">const</span> router = useRouter()

    React.useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (user == <span class="hljs-literal">null</span>) router.push(<span class="hljs-string">"/"</span>)
    }, [user])

    <span class="hljs-keyword">return</span> (<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Only logged in users can view this page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>);
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Page;
</code></pre>
<p>If the <code>user</code> is <code>null</code> we are simply redirecting the user to the homepage. If the user is not <code>null</code>, we show them the protected page.</p>
<h2 id="heading-how-to-communicate-with-our-database">How to Communicate with Our Database</h2>
<p>Now that we have gotten the Authentication part of the way, we can focus on communication with our database. For our database we are going to use <strong>Firestore.</strong></p>
<p>Again to make things more tidy, create a new <strong>firebase &gt; firestore</strong> directory, inside this directory we'll add all our Firestore-related code.</p>
<h3 id="heading-how-to-add-documents-to-firestore">How to Add Documents to Firestore</h3>
<p>Create a file called <code>addData.js</code> inside the <strong>firestore</strong> directory and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> firebase_app <span class="hljs-keyword">from</span> <span class="hljs-string">"../config"</span>;
<span class="hljs-keyword">import</span> { getFirestore, doc, setDoc } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/firestore"</span>;

<span class="hljs-keyword">const</span> db = getFirestore(firebase_app)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addData</span>(<span class="hljs-params">colllection, id, data</span>) </span>{
    <span class="hljs-keyword">let</span> result = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">let</span> error = <span class="hljs-literal">null</span>;

    <span class="hljs-keyword">try</span> {
        result = <span class="hljs-keyword">await</span> setDoc(doc(db, colllection, id), data, {
            <span class="hljs-attr">merge</span>: <span class="hljs-literal">true</span>,
        });
    } <span class="hljs-keyword">catch</span> (e) {
        error = e;
    }

    <span class="hljs-keyword">return</span> { result, error };
}
</code></pre>
<p>At this point this type of code should be familiar to you. We're exporting a function that adds data to our firestore database.</p>
<p>We can now use this <code>addData()</code> function from any component to add data to our database:</p>
<pre><code class="lang-js"><span class="hljs-string">'use client'</span>
<span class="hljs-keyword">import</span> addData <span class="hljs-keyword">from</span> <span class="hljs-string">"@/firebase/firestore/addData"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-keyword">const</span> handleForm = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> data = {
      <span class="hljs-attr">name</span>: <span class="hljs-string">'John snow'</span>,
      <span class="hljs-attr">house</span>: <span class="hljs-string">'Stark'</span>
    }
    <span class="hljs-keyword">const</span> { result, error } = <span class="hljs-keyword">await</span> addData(<span class="hljs-string">'users'</span>, <span class="hljs-string">'user-id'</span>, data)

    <span class="hljs-keyword">if</span> (error) {
      <span class="hljs-keyword">return</span> <span class="hljs-built_in">console</span>.log(error)
    }
  }

  <span class="hljs-keyword">return</span> (
    ...
  )
}
</code></pre>
<h3 id="heading-how-to-get-a-document-from-firestore">How to Get a Document from Firestore</h3>
<p>Using a similar approach, we can get a document from our Firestore database.</p>
<p>Create a <code>getData.js</code> file in the <strong>Firestore</strong> directory and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> firebase_app <span class="hljs-keyword">from</span> <span class="hljs-string">"../config"</span>;
<span class="hljs-keyword">import</span> { getFirestore, doc, getDoc } <span class="hljs-keyword">from</span> <span class="hljs-string">"firebase/firestore"</span>;

<span class="hljs-keyword">const</span> db = getFirestore(firebase_app)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getDoument</span>(<span class="hljs-params">collection, id</span>) </span>{
    <span class="hljs-keyword">let</span> docRef = doc(db, collection, id);

    <span class="hljs-keyword">let</span> result = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">let</span> error = <span class="hljs-literal">null</span>;

    <span class="hljs-keyword">try</span> {
        result = <span class="hljs-keyword">await</span> getDoc(docRef);
    } <span class="hljs-keyword">catch</span> (e) {
        error = e;
    }

    <span class="hljs-keyword">return</span> { result, error };
}
</code></pre>
<p>You can also use the <code>getData()</code> in any component you choose.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we learned how to build a full stack application using Firebase and Next.js 13 by integrating authentication and interacting with our database.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ JavaScript DOM Tutorial – How to Build a Calculator App in JS ]]>
                </title>
                <description>
                    <![CDATA[ You're going to spend a lot of time working on webpages when using JavaScript. In fact, while you're using JavaScript, the webpage is where all the exciting and important stuff takes place. A webpage is one big document for a JavaScript developer sin... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/javascript-dom-build-a-calculator-app/</link>
                <guid isPermaLink="false">66d461604a0edd9b48e8359b</guid>
                
                    <category>
                        <![CDATA[ DOM ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Spruce Emmanuel ]]>
                </dc:creator>
                <pubDate>Fri, 02 Sep 2022 15:40:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/Web-capture_31-8-2022_83456_localhost.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>You're going to spend a lot of time working on webpages when using JavaScript. In fact, while you're using JavaScript, the webpage is where all the exciting and important stuff takes place.</p>
<p>A webpage is one big document for a JavaScript developer since every element on the page is connected (like a big family). It's all made up of parents (parentNodes) and children (childNodes). The Document Object Model is the name of this family (DOM).</p>
<p>In this article, you'll learn about the DOM along with loops and events by building a simple iOS calculator app.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-the-dom">What is the DOM?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-select-elements-in-the-dom">How to Select Elements in the DOM</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-and-add-elements-to-the-dom">How to Create and Add Elements to the DOM</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-modify-elements-in-the-dom">How to Modify Elements in the DOM</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-remove-elements-from-the-dom">How to Remove Elements from the DOM</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-loops-and-iterations">Loops and Iterations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-dom-events">DOM Events</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-javascript-event-handling">JavaScript Event Handling</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-the-calculator-app">How to Build the Calculator App</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-functionality-to-the-calculator">How to Add Functionality to the Calculator</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p><strong>So, what are you going to need to make the most of this tutorial?</strong></p>
<p>You'll need a browser, a text editor (Vscode), and some basic JavaScript knowledge. For a head start, I recommend checking out <a target="_blank" href="https://www.freecodecamp.org/news/learn-javascript-free-js-courses-for-beginners/">one of these great introductory courses</a>.</p>
<p>You can also read this great article on <a target="_blank" href="https://www.freecodecamp.org/news/learn-javascript-by-building-a-project/">JavaScript Fundamentals</a>.</p>
<p>If you've already read the article and participated in the challenge, here's my simple solution.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/Spruce_khalifa/embed/PoRLqGL" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>This article also assumes you have a basic understanding of HTML and CSS, as well as how the web works.</p>
<p>With that, let's dive in.</p>
<h2 id="heading-what-is-the-dom">What is the DOM?</h2>
<p>The Document Object Model (DOM) is a logical structure that defines how elements in a document can be manipulated and changed. Because the DOM is a structured this way, it is commonly referred to as a tree in which everything is connected.</p>
<p>Here's an example:</p>
<p><img src="https://lh4.googleusercontent.com/F2-Cq8eWERd3pCUseD4CprU2HNN1pg7Bp-znXM5KF5XjB60ADt4HVggy9bmpGzo_1rcrrqjfGbNWywdpoaONDU-3asY4FlNdqjscx6y_X4h-iTgIu60E11IYE26zmKTC2nXcQi0k1OfkkHR3t5snxtI" alt="Image" width="1234" height="504" loading="lazy"></p>
<p>You can access, modify, delete, or add new elements or content to a document using the DOM. In summary, the DOM allows you to manipulate almost everything on a webpage.</p>
<p>Roll up your sleeves and let's get right to work now that we have a better understanding of what the DOM is.</p>
<h2 id="heading-how-to-select-elements-in-the-dom">How to Select Elements in the DOM</h2>
<p>One of the very first things you’ll do when working with the DOM is to select elements in the document.</p>
<p>In fact, you must first learn how to access elements in the DOM before you can manipulate it.</p>
<p>You can select (or access) elements in a few different ways. Below, we'll go over the few that you'll need the most.</p>
<h3 id="heading-how-to-select-dom-elements-by-id">How to Select DOM Elements by ID</h3>
<p>With <code>getElementById(),</code> you may select any element on a webpage that has an <code>id</code>. All you need to do is pass in the <code>id</code> of the element you wish to select.</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"btn"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
...
</code></pre>
<p>Here's the JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> button = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"btn"</span>);

<span class="hljs-built_in">console</span>.log(button)
</code></pre>
<p>It is important to remember that the <code>getElementById</code> method only selects the first element on a page if there are many items with the same id. Note that an id should be unique and you should never have multiple elements with the same id.</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"btn"</span>&gt;</span>one<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"btn"</span>&gt;</span>two<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"btn"</span>&gt;</span>three<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
...
</code></pre>
<p>And here's the JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> button = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"button"</span>);

<span class="hljs-built_in">console</span>.log(button); <span class="hljs-comment">// only the first button is selected</span>
</code></pre>
<h3 id="heading-how-to-select-dom-elements-by-class-name">How to Select DOM Elements by Class Name</h3>
<p>You can use the <code>getElementsByClassName</code> method to select any element that has a class:</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn"</span>&gt;</span>Submit<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
...
</code></pre>
<p>The JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> button = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"btn"</span>);

<span class="hljs-built_in">console</span>.log(button);
</code></pre>
<p>Keep in mind that it says getElements – Elements with an "s". This indicates that all items with the class <code>btn</code> will be selected by the selector, and they will all be added to an <code>HTMLCollection</code> (an array). You do remember what an array is, don't you?</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn"</span>&gt;</span>one<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn"</span>&gt;</span>two<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn"</span>&gt;</span>three<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      ...
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
...
</code></pre>
<p>The JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> buttons = <span class="hljs-built_in">document</span>.getElementsByClassName(<span class="hljs-string">"btn"</span>);

<span class="hljs-built_in">console</span>.log(buttons); <span class="hljs-comment">// returns an HTMLCollection of all the buttons</span>
</code></pre>
<h3 id="heading-how-to-select-dom-elements-by-tag-name">How to Select DOM Elements by Tag Name</h3>
<p>This works in a similar way to <code>getElementsByClassName</code>: it returns an HTMLCollection of all the Tags found in the document.</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"article"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is a paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the second paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the third paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is fourth paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
...
</code></pre>
<p>The JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> p_tag = <span class="hljs-built_in">document</span>.getElementsByTagName(<span class="hljs-string">"p"</span>);

<span class="hljs-built_in">console</span>.log(p_tag);
</code></pre>
<h3 id="heading-how-to-select-elements-by-using-css-selectors">How to Select Elements by Using CSS Selectors</h3>
<p>Here are my favorite selectors: <code>querySelector()</code> and <code>querySelectorAll()</code>. With these selectors, you can select any element in the DOM the same way you'd select any element with CSS</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> img = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"img"</span>); <span class="hljs-comment">// select element by tag name</span>
<span class="hljs-keyword">const</span> input = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"input[type='text']"</span>);
<span class="hljs-keyword">const</span> last_div = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"form &gt; *:last-child"</span>);
<span class="hljs-keyword">const</span> button = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".btn"</span>) <span class="hljs-comment">// select element by class name</span>
<span class="hljs-keyword">const</span> button = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"#btn"</span>) <span class="hljs-comment">// select element by id</span>
</code></pre>
<p>You use <code>querySelector()</code> to select a single element. If the selector matches many elements on the page, just the first one is returned.</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"article"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is a paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the second paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the third paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is fourth paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
...
</code></pre>
<p>The JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> p_tag = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"p"</span>)

<span class="hljs-built_in">console</span>.log(p_tag)
</code></pre>
<p><code>querySelectorAll()</code>, on the other hand, will select all the items in the document that match the selector and store them in a NodeList (an array) similar to the ones seen above.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> p_tags = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">"p"</span>);

<span class="hljs-built_in">console</span>.log(p_tags);
</code></pre>
<p>It's worth noting that when you use <code>document.querySelector()</code>, you're searching the whole document for the element. But when you perform <code>element.querySelector()</code>, you're only searching the selected element.</p>
<p>Consider the following example: <code>querySelector()</code>. The selector will only look for items that match within the element.</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn"</span>&gt;</span>one<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn"</span>&gt;</span>two<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn"</span>&gt;</span>two<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn"</span>&gt;</span>button one outside the form<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn"</span>&gt;</span>button two outside the form<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
...
</code></pre>
<p>The JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> form = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"form"</span>)

<span class="hljs-keyword">const</span> form_btns = form.querySelectorAll(<span class="hljs-string">".btn"</span>)

<span class="hljs-built_in">console</span>.log(form_btns); <span class="hljs-comment">// only buttons within the form will get selected</span>
</code></pre>
<p>The <code>form.querySelectorAll()</code> will only select the buttons within the form. This also applies to all elements and selectors.</p>
<h2 id="heading-how-to-create-and-add-elements-to-the-dom">How to Create and Add Elements to the DOM</h2>
<p>After learning how to select HTML elements that have already been created in the DOM, let's try creating our own elements using JavaScript.</p>
<p>There are a few steps to take in order to add elements to the DOM using JavaScript. We'll go over each of them below.</p>
<h3 id="heading-how-to-create-a-dom-element">How to Create a DOM Element</h3>
<p>JavaScript requires that any element be created before it can be added to the DOM. For this, we use the <code>document.createElement()</code> method.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> new_div = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
<span class="hljs-keyword">const</span> new_paragraph = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"p"</span>);
<span class="hljs-keyword">const</span> new_link = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"a"</span>);
<span class="hljs-keyword">const</span> new_image = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"img"</span>);
</code></pre>
<p>We just created the above tags in JavaScript and have not yet added them to the DOM. Nonetheless, they are still simply tags with no attributes or text content, so let's correct that right away.</p>
<h3 id="heading-how-to-set-attributes-of-elements">How to Set Attributes of Elements</h3>
<p>To set the attributes, such as adding a class, changing the ID, or changing the SRC, we simply use the <code>setAttribute()</code> method on the new element.</p>
<p>The <code>setAttribute("attribute", "value")</code> method takes two parameters, the attribute and the value to be applied to the attribute.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> new_div = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
<span class="hljs-keyword">const</span> new_paragraph = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"p"</span>);
<span class="hljs-keyword">const</span> new_link = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"a"</span>);
<span class="hljs-keyword">const</span> new_image = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"img"</span>);

<span class="hljs-comment">// setting the attributes</span>
new_div.setAttribute(<span class="hljs-string">"class"</span>, <span class="hljs-string">"my_div"</span>); <span class="hljs-comment">// setting a class attribute</span>
new_paragraph.setAttribute(<span class="hljs-string">"id"</span>, <span class="hljs-string">"my_paragraph"</span>); <span class="hljs-comment">// setting an id attribute</span>
new_link.setAttribute(<span class="hljs-string">"href"</span>, <span class="hljs-string">"https://example.com"</span>); <span class="hljs-comment">// setting the href attribute</span>
new_image.setAttribute(<span class="hljs-string">"src"</span>, <span class="hljs-string">"https://image-link.png"</span>); <span class="hljs-comment">// setting the src attribut of image</span>
</code></pre>
<h3 id="heading-how-to-add-the-text-content">How to Add the Text Content</h3>
<p>Some of our newly created elements still require text to be added to them in order for us to use them in the document – even after attributes have been added.</p>
<p>To create the texts and add them to our newly created elements, use the method <code>createTextNode()</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> new_div = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
<span class="hljs-keyword">const</span> new_paragraph = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"p"</span>);
<span class="hljs-keyword">const</span> new_link = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"a"</span>);
<span class="hljs-keyword">const</span> new_image = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"img"</span>);

...

<span class="hljs-comment">// creating the textNodes</span>
<span class="hljs-keyword">const</span> new_div_text = <span class="hljs-built_in">document</span>.createTextNode(<span class="hljs-string">"Hello world"</span>);
<span class="hljs-keyword">const</span> new_paragraph_text = <span class="hljs-built_in">document</span>.createTextNode(<span class="hljs-string">"This is a paragraph"</span>);
<span class="hljs-keyword">const</span> new_link_text = <span class="hljs-built_in">document</span>.createTextNode(<span class="hljs-string">"Click to visit link"</span>);

<span class="hljs-comment">// append the textsNodes to the elements</span>
new_div.append(new_div_text);
new_paragraph.append(new_paragraph_text);
new_link.append(new_link_text);

<span class="hljs-built_in">console</span>.log(new_div, new_paragraph, new_link, new_image);
</code></pre>
<p>And from here, we can actually add the newly created element to the DOM.</p>
<h3 id="heading-how-to-add-elements-to-the-dom">How to Add Elements to the DOM</h3>
<p>The sole way to add newly created elements to the DOM is by inserting them into an existing element.</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
...
</code></pre>
<p>The JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> new_div = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
<span class="hljs-keyword">const</span> new_paragraph = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"p"</span>);
<span class="hljs-keyword">const</span> new_link = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"a"</span>);
<span class="hljs-keyword">const</span> new_image = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"img"</span>);

...

<span class="hljs-comment">// adding elements to the DOM</span>

<span class="hljs-comment">// selecting parent element</span>
<span class="hljs-keyword">const</span> container = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".container"</span>);

container.appendChild(new_div);
container.appendChild(new_paragraph);
container.appendChild(new_link);
container.appendChild(new_image);
</code></pre>
<p>The new element will be added as a child to the already selected existing element using the <code>appendChild()</code> method.</p>
<p>There are, of course, more ways to add new elements to the DOM, but I'll leave them for your own reading.</p>
<h2 id="heading-how-to-modify-elements-in-the-dom">How to Modify Elements in the DOM</h2>
<p>In addition to creating and adding elements to the DOM, JavaScript also allows us to modify already-existing DOM elements. We can change their contents, add or remove attributes, or even change their styles.</p>
<h3 id="heading-how-to-modify-text">How to Modify Text</h3>
<p>Use <code>textContent</code> or <code>innerText</code> to modify the text of any element. See the example below:</p>
<pre><code class="lang-js">...
  &lt;body&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"article"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is a paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span></span>
  &lt;/body&gt;
...
</code></pre>
<p>The JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> p_tag = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"article p"</span>);

<span class="hljs-comment">// modify text content using textContent</span>
p_tag.textContent = <span class="hljs-string">"Override existing text"</span>;

<span class="hljs-comment">// modify text content using innerText</span>
p_tag.innerText = <span class="hljs-string">"Override existing text using innerText"</span>;
</code></pre>
<p>Aside from text we can also modify attributes.</p>
<h3 id="heading-how-to-modify-attributes">How to Modify Attributes</h3>
<p>You can use the <code>setAttribute()</code> method to change any attribute that an element may have had in addition to adding new ones, as we have already seen in a previous section.</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"article"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"my_paragraph"</span>&gt;</span>This is a paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
...
</code></pre>
<p>The JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> p_tag = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"article p"</span>);

p_tag.setAttribute(<span class="hljs-string">"class"</span>, <span class="hljs-string">"new_paragraph"</span>);

<span class="hljs-built_in">console</span>.log(p_tag);
</code></pre>
<p>Since we're talking about changing attributes, we can also add, delete, and toggle between adding and deleting a class attribute to an element using the <code>classList.add()</code>, <code>classList.remove()</code>, and <code>classList.toggle()</code> methods, respectively.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> p_tag = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"article p"</span>);

p_tag.classList.add(<span class="hljs-string">"active"</span>) <span class="hljs-comment">// add a new tag</span>
p_tag.classList.remove(<span class="hljs-string">"active"</span>) <span class="hljs-comment">// remove a class</span>
p_tag.classList.toggle(<span class="hljs-string">"active"</span>) <span class="hljs-comment">// would remove the class if it exits or add it if it dosen't</span>
</code></pre>
<h3 id="heading-how-to-modify-element-styles">How to Modify Element Styles</h3>
<p>You may change the styles of elements directly in JavaScript. Simply select the element and add the style property followed by the CSS style you want to use.</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is a paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
...
</code></pre>
<p>The JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> container = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".container"</span>);

container.style.display = <span class="hljs-string">"none"</span>;
</code></pre>
<p>You can add any CSS style you want. The main difference is that CSS properties are separated by hyphens (-), for example, <code>background-color</code>. But in JavaScript CSS properties are written in camelCase – <code>backgroundColor</code>.</p>
<pre><code class="lang-js">container.style.backgroundColor = <span class="hljs-string">"red"</span>;
</code></pre>
<h2 id="heading-how-to-remove-elements-from-the-dom">How to Remove Elements from the DOM</h2>
<p>Whatever can be created can also be deleted, including elements in the DOM. For example, you can remove the child of a parent element by using <code>removeChild()</code>. Similarly, you can remove the p element in the div below by using <code>removeChild()</code>:</p>
<pre><code class="lang-html">...
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is a paragraph<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
...
</code></pre>
<p>The JavaScript:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> parent_element = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".container"</span>);
<span class="hljs-keyword">const</span> child_element = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".container p"</span>);

parent_element.removeChild(child_element);
</code></pre>
<p>Above we selected the parent element and then removed the child. You can also just remove the <code>p</code> directly by using <code>remove()</code>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> child_element = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".container p"</span>);

child_element.remove();
</code></pre>
<p>It is entirely up to you how you delete elements.</p>
<h2 id="heading-loops-and-iterations">Loops and Iterations</h2>
<p>Loops let us accomplish repeated tasks, such as printing a number numerous times or iterating through an array.</p>
<p>With loops, we can access every item in an array, as seen in the example below, where we print out all the elements in an array.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> my_array = [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-string">"hello"</span>, <span class="hljs-number">55</span>, <span class="hljs-string">"60"</span>, <span class="hljs-string">"JavaScript"</span>];

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; my_array.length; i++) {
  <span class="hljs-keyword">const</span> item = my_array[i];

  <span class="hljs-built_in">console</span>.log(item);
}
</code></pre>
<p>The code above would print out every item in the array until it reaches the last one when you execute it.</p>
<p>But what if we wanted to stop at a certain point? You can use the <code>break</code> statement to exit a loop. For instance, we might decide to stop printing the elements in that array when we reach the fifth one.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> my_array = [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-string">"hello"</span>, <span class="hljs-number">55</span>, <span class="hljs-string">"60"</span>, <span class="hljs-string">"JavaScript"</span>];

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; my_array.length; i++) {
  <span class="hljs-keyword">const</span> item = my_array[i];

  <span class="hljs-keyword">if</span> (i == <span class="hljs-number">5</span>) {
    <span class="hljs-keyword">break</span>;
  }

  <span class="hljs-built_in">console</span>.log(item);
}
</code></pre>
<p>The break statement terminates the loop's execution.</p>
<p>You see, many years ago, the for loop (the loop above) was a great method to iterate over items in an array. But since the world and JavaScript have changed, we now have fancier and quicker ways to iterate over arrays. Now we're going to explore the most common ones.</p>
<h3 id="heading-how-to-use-the-foreach-and-map-methods">How to Use the <code>forEach()</code> and <code>map()</code> Methods</h3>
<p>The <code>forEach()</code> method is one of the new fancy ways of looping over arrays. The <code>forEach()</code> method will loop through the array and run a function that you define for each item in the array.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> my_array = [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-string">"hello"</span>, <span class="hljs-number">55</span>, <span class="hljs-string">"60"</span>, <span class="hljs-string">"JavaScript"</span>];

my_array.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">item</span>) </span>{
  <span class="hljs-built_in">console</span>.log(item);
});
</code></pre>
<p>It's even shorter when you're using arrow functions:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> my_array = [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-string">"hello"</span>, <span class="hljs-number">55</span>, <span class="hljs-string">"60"</span>, <span class="hljs-string">"JavaScript"</span>];

my_array.forEach(<span class="hljs-function">(<span class="hljs-params">item</span>) =&gt;</span> <span class="hljs-built_in">console</span>.log(item));
</code></pre>
<p>The function you provide must take at least a one parameter which is the current item in the array. The other two parameters are optional: the index (the current item's index, which is a number) and the last parameter is the original array that you're looping through.</p>
<pre><code class="lang-js">my_array.forEach(callback_function, index, original_array)
</code></pre>
<p>The only difference between <code>Array.map()</code> and <code>Array.forEach()</code> is that <code>Array.map()</code> will return a new array after the callback function, whereas <code>Array.forEach()</code> does not return any. <code>Array.map()</code> will do exactly what <code>Array.forEach()</code> will do, which is execute a function for each item in the array.</p>
<p>In contrast to the for loop, the break statement is ineffective in the <code>Array.forEach()</code> and <code>Array.map()</code> methods.</p>
<h3 id="heading-the-forof-loop">The for...of Loop</h3>
<p>The for...of loop, which accepts a variable and the array you want to iterate over, is one of the new fancy ways we may loop over any iterable item.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> my_array = [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-string">"hello"</span>, <span class="hljs-number">55</span>, <span class="hljs-string">"60"</span>, <span class="hljs-string">"JavaScript"</span>];

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> item <span class="hljs-keyword">of</span> my_array) {
  <span class="hljs-built_in">console</span>.log(item);
}
</code></pre>
<p>Just like in a regular loop, the break statement can be used in a for...of loop.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> my_array = [<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-string">"hello"</span>, <span class="hljs-number">55</span>, <span class="hljs-string">"60"</span>, <span class="hljs-string">"JavaScript"</span>];

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> item <span class="hljs-keyword">of</span> my_array) {
  <span class="hljs-built_in">console</span>.log(item);
  <span class="hljs-keyword">if</span> (item &gt;= <span class="hljs-number">6</span>) {
    <span class="hljs-keyword">break</span>;
  }
}
</code></pre>
<h2 id="heading-dom-events">DOM Events</h2>
<p>Users will engage in a variety of actions when using your application, such as clicking buttons, hovering over items on the screen, submitting forms, refreshing pages, and other activities that users enjoy.</p>
<p>In JavaScript, all of these user interactions are referred to as Events.</p>
<p>There are many events in JavaScript, thus it contains event listeners that may be used to respond to each one. However, we're only going to talk about the most typical ones in this post.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Event</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>click</td><td>When a user clicks an element, this event is triggered.</td></tr>
<tr>
<td>mouseover</td><td>Hovering over elements in the DOM causes this event to be triggered.</td></tr>
<tr>
<td>input</td><td>When the value of an input or select element changes, this event is fired.</td></tr>
<tr>
<td>submit</td><td>When a form is submitted, this event is triggered</td></tr>
<tr>
<td>keydown</td><td>When a keyboard key is pushed, the keydown event is triggered.</td></tr>
<tr>
<td>Keyup</td><td>Fired when a pushed key is released. It is the opposite of Keydown.</td></tr>
<tr>
<td>DOMContentLoaded</td><td>This event is fired when the DOM has loaded, but this event is fired before any external resource(like css and images) is downloaded.</td></tr>
<tr>
<td>load</td><td>On the other hand, this event won't be triggered until all DOM elements, including external resources, have loaded.</td></tr>
</tbody>
</table>
</div><p>There are many other events in JavaScript, but we'll stop here. You can view additional events in the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Events">MDN DOM event reference</a>.</p>
<p>Now that we've seen several types of events, let's see how we might respond to them.</p>
<h2 id="heading-javascript-event-handling">JavaScript Event Handling</h2>
<p>The addEventListener method is the recommended way to handle events in JavaScript. This method allows you to define a function that will be executed whenever the event you specify is triggered.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> input = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"input[type='text']"</span>);

<span class="hljs-keyword">const</span> handle_input = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(e.target.value);
};

input.addEventListener(<span class="hljs-string">"input"</span>, handle_input);
</code></pre>
<p>The function you pass into the <code>addEventListener()</code> method will accept one argument: a reference to the Event Object, which has a set of properties that describe the event that just happened.</p>
<p>You can also remove an event listener from an element using the <code>removeEventListener()</code>. This method must take the exact same function as the one you passed into the <code>addEventListener()</code> method.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> input = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">"input[type='text']"</span>);

<span class="hljs-keyword">const</span> handle_input = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(e.target.value)
};

<span class="hljs-keyword">const</span> handle_input2 = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(e.target.value);
  <span class="hljs-built_in">console</span>.log(e);
};

input.removeEventListener(<span class="hljs-string">"input"</span>, handle_input); <span class="hljs-comment">// this will work</span>

input.removeEventListener(<span class="hljs-string">"input"</span>, handle_input2); <span class="hljs-comment">// passing in a different function will not work</span>
</code></pre>
<p>And for now that's all for events and event handling. Enough of the talk, let's practice all we've be learning so far.</p>
<h2 id="heading-how-to-build-the-calculator-app">How to Build the Calculator App</h2>
<p>We're going to build the basic iPhone calculator to put our new JavaScript skills to the test. To get started, create an HTML file, a CSS file, and then a JavaScript file.</p>
<p>By now, I assume you know how to set up a basic environment using those three tools. You may use an online code editor like CodePen, which is what I'll be doing in this lesson, if you don't have access to a PC where you can generate those files.</p>
<p>We'll begin by building the foundation of our application. Open the HTML file you prepared and paste the following code into it.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"X-UA-Compatible"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"IE=edge"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>iPhone Calculator<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">defer</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"script.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"main"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"calc_form"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"calc_header"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">disabled</span>
            <span class="hljs-attr">id</span>=<span class="hljs-string">"output"</span>
            <span class="hljs-attr">class</span>=<span class="hljs-string">"calc_output"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">"0"</span>
          /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">footer</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"calc_footer"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">data-type</span>=<span class="hljs-string">"clear"</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"reset"</span>
              <span class="hljs-attr">value</span>=<span class="hljs-string">"clear"</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-grey"</span>
            &gt;</span>
              AC
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operator"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"invert"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-grey"</span>&gt;</span>
              +/-
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operator"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"%"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-grey"</span>&gt;</span>
              %
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operator"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-orange"</span>&gt;</span>
              ÷
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span>
              <span class="hljs-attr">value</span>=<span class="hljs-string">"7"</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>
              <span class="hljs-attr">id</span>=<span class="hljs-string">"7"</span>
            &gt;</span>
              7
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"8"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>&gt;</span>
              8
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"9"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>&gt;</span>
              9
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operator"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"*"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-orange"</span>&gt;</span>
              x
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>&gt;</span>
              4
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"5"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>&gt;</span>
              5
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"6"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>&gt;</span>
              6
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operator"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"-"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-orange"</span>&gt;</span>
              -
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"1"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>&gt;</span>
              1
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"2"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>&gt;</span>
              2
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"3"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>&gt;</span>
              3
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operator"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"+"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-orange"</span>&gt;</span>
              +
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn_group"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span>
              <span class="hljs-attr">value</span>=<span class="hljs-string">"0"</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-grow btn-dark-grey"</span>
            &gt;</span>
              0
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"."</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>&gt;</span>
              .
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"="</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operator"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-orange"</span>&gt;</span>
              =
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>As you can see above, our calculator is basically an HTML form with a lot of buttons and an input field. To style it, let's add some CSS so that it resembles the calculator on iPhones. Open the CSS file you made and add the following code:</p>
<pre><code class="lang-css">*,
*<span class="hljs-selector-pseudo">::after</span>,
*<span class="hljs-selector-pseudo">::before</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0px</span>;
  <span class="hljs-attribute">font-family</span>: inherit;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#333333</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
}

<span class="hljs-selector-tag">body</span>,
<span class="hljs-selector-tag">html</span> {
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">font-family</span>: sans-serif;
}

<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">0px</span>;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"text"</span>]</span> {
  <span class="hljs-attribute">background-color</span>: transparent;
  <span class="hljs-attribute">text-align</span>: end;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#d2d2d2</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">0px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">4rem</span>;
}

<span class="hljs-selector-id">#main</span> {
  <span class="hljs-attribute">border</span>: <span class="hljs-number">2px</span> solid <span class="hljs-number">#ededed</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50px</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">280px</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#000000</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span> <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.calc_header</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">90px</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">12px</span>;
}

<span class="hljs-selector-class">.calc_footer</span> &gt; * + * {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.calc_footer</span> &gt; *<span class="hljs-selector-pseudo">:last-child</span> {
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.btn_group</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: space-between;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.3rem</span>;
}

<span class="hljs-selector-class">.btn</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">60px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">60px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#ffffff</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
  <span class="hljs-attribute">transition</span>: all <span class="hljs-number">0.3s</span> <span class="hljs-built_in">cubic-bezier</span>(<span class="hljs-number">0.19</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0.22</span>, <span class="hljs-number">1</span>);
}

<span class="hljs-selector-class">.btn</span><span class="hljs-selector-class">.btn-grow</span> {
  <span class="hljs-attribute">flex-grow</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">40px</span>;
}

<span class="hljs-selector-class">.btn</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(-<span class="hljs-number">2px</span>, -<span class="hljs-number">3px</span>);
}

<span class="hljs-selector-class">.btn</span><span class="hljs-selector-class">.active</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ffffff</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#f69906</span>;
}

<span class="hljs-selector-class">.btn-grey</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#9f9f9f</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#000</span>;
}

<span class="hljs-selector-class">.btn-grey</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ededed</span>;
}

<span class="hljs-selector-class">.btn-dark-grey</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#313131</span>;
}

<span class="hljs-selector-class">.btn-dark-grey</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#999999</span>;
}

<span class="hljs-selector-class">.btn-orange</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f69906</span>;
}

<span class="hljs-selector-class">.btn-orange</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: orange;
}
</code></pre>
<p>And now, we have a simple calculator application with no functionality at this time. This is how the live preview appears:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/freeCodeCamp/embed/jOpwqmR" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>From the example above, whenever you click a button, the form is submitted and the page is reloaded. But we don't want that to happen.</p>
<p>If you recall from the Events section, we discussed the submit event that is fired whenever we submit a form. We can use that event to stop our form from submitting whenever we click a button.</p>
<p>To do this, open the JavaScript file you created and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> form = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"calc_form"</span>);

form.addEventListener(<span class="hljs-string">"submit"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  e.preventDefault();
});
</code></pre>
<p>If you return to the HTML code above and pay close attention, you will see that each button has a value property and a data-type attribute that is either operator or operand:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operand"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"6"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-dark-grey"</span>&gt;</span>
6
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">data-type</span>=<span class="hljs-string">"operator"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"-"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-orange"</span>&gt;</span>
-
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>The reason for this is so that we can distinguish between numbers (operands) and operators when selecting buttons in JavaScript.</p>
<h3 id="heading-how-to-add-functionality-to-the-calculator">How to Add Functionality to the Calculator</h3>
<p>Now that we've done this, we can begin adding functionality to our application.</p>
<p>To begin, let's display the values of our operands when we click on the buttons. Add the following code to your JavaScript file.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> output = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"output"</span>);
<span class="hljs-keyword">const</span> form = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"calc_form"</span>);
<span class="hljs-keyword">const</span> operand_btns = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">"button[data-type=operand]"</span>);
...
let is_operator = <span class="hljs-literal">false</span>;
operand_btns.forEach(<span class="hljs-function">(<span class="hljs-params">btn</span>) =&gt;</span> {
  btn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (output.value == <span class="hljs-string">"0"</span>) {
      output.value = e.target.value;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (is_operator) {
      is_operator = <span class="hljs-literal">false</span>;
      output.value = e.target.value;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (output.value.includes(<span class="hljs-string">"."</span>)) {
      output.value = output.value + <span class="hljs-string">""</span> + e.target.value.replace(<span class="hljs-string">"."</span>, <span class="hljs-string">""</span>);
    } <span class="hljs-keyword">else</span> {
      output.value = output.value + <span class="hljs-string">""</span> + e.target.value;
    }
  });
});
</code></pre>
<p>Instead of selecting all the buttons one after the other (which is tedious by the way) we used the <code>querySelectorAll()</code>. This will select all the buttons we specified and put them in a NodeList (an array with node items).</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> operand_btns = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">"button[data-type=operand]"</span>);
</code></pre>
<p>If you remember what we discussed in the Loops and Iteration section, you cannot access any of those selected buttons unless you iterate over the array using one of the loop methods we discussed in that section.</p>
<pre><code class="lang-js">operand_btns.forEach(<span class="hljs-function">(<span class="hljs-params">btn</span>) =&gt;</span> {
  <span class="hljs-comment">// you can access each button here</span>
});
</code></pre>
<p>Lastly we added a <code>click</code> event listener to each button like this:</p>
<pre><code class="lang-js">btn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  <span class="hljs-comment">// control what happens when a button is clicked</span>
});
</code></pre>
<p>Now, whenever we click on any operand value, the value of that number is displayed on the calculator.</p>
<p>In the <code>else..if</code> statement, we check if there is a decimal in our output value. If there is, we simply stop adding any further decimal point by replacing it with an empty string.</p>
<pre><code class="lang-js">output.value = output.value + <span class="hljs-string">""</span> + e.target.value.replace(<span class="hljs-string">"."</span>, <span class="hljs-string">""</span>);
</code></pre>
<p>Another <code>else..if</code> statement checks to see whether we've previously clicked on an operator button. If we have and then click on an operand button, we want to set the <code>is_operator</code> value to false and restart the value in the output from the new value.</p>
<pre><code class="lang-js"><span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (is_operator) {
  is_operator = <span class="hljs-literal">false</span>;
  output.value = e.target.value;
}
</code></pre>
<p>Here is the live preview of the example above:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/freeCodeCamp/embed/yLqXOgm" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>Now let's also select the buttons with <code>data-type</code> operator and specify what will happen whenever we click on any of the buttons.</p>
<p>Open your JavaScript file and add the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> operator_btns = <span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">"button[data-type=operator]"</span>);
...
let equation = [];
operator_btns.forEach(<span class="hljs-function">(<span class="hljs-params">btn</span>) =&gt;</span> {
  btn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.currentTarget.classList.add(<span class="hljs-string">"active"</span>);

    <span class="hljs-keyword">switch</span> (e.target.value) {
      <span class="hljs-keyword">case</span> <span class="hljs-string">"%"</span>:
        output.value = <span class="hljs-built_in">parseFloat</span>(output.value) / <span class="hljs-number">100</span>;
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">"invert"</span>:
        output.value = <span class="hljs-built_in">parseFloat</span>(output.value) * <span class="hljs-number">-1</span>;
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">case</span> <span class="hljs-string">"="</span>:
        equation.push(output.value);
        output.value = <span class="hljs-built_in">eval</span>(equation.join(<span class="hljs-string">""</span>));
        equation = [];
        <span class="hljs-keyword">break</span>;
      <span class="hljs-keyword">default</span>:
        <span class="hljs-keyword">let</span> last_item = equation[equation.length - <span class="hljs-number">1</span>];
        <span class="hljs-keyword">if</span> ([<span class="hljs-string">"/"</span>, <span class="hljs-string">"*"</span>, <span class="hljs-string">"+"</span>, <span class="hljs-string">"-"</span>].includes(last_item) &amp;&amp; is_operator) {
          equation.pop();
          equation.push(e.target.value);
        } <span class="hljs-keyword">else</span> {
          equation.push(output.value);
          equation.push(e.target.value);
        }
        is_operator = <span class="hljs-literal">true</span>;
        <span class="hljs-keyword">break</span>;
    }
  });
});
</code></pre>
<p>The first thing we do in the code above, after adding a click event listener to our button, is add the class <code>active</code> to any operator buttons that we click. We have previously defined the styling for this active class in our CSS.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.btn</span><span class="hljs-selector-class">.active</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#ffffff</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#f69906</span>;
}
</code></pre>
<p>We want to apply those styles on the button we just clicked whenever we press the operator button.</p>
<p>We could have used an <code>if..else</code> statement here as well, but who says we can't try new things? The switch statement that follows is a conditional statement in JavaScript, much like the if statement we have been seeing.</p>
<p>The <code>switch</code> statement accepts a value (the condition), in this example the value of the button that was clicked. For each case, the value is checked. In the first case a <code>%</code> simply converts the number in the output to a percentage.</p>
<pre><code class="lang-js"><span class="hljs-keyword">case</span> <span class="hljs-string">"%"</span>:
  output.value = <span class="hljs-built_in">parseFloat</span>(output.value) / <span class="hljs-number">100</span>;
  <span class="hljs-keyword">break</span>;
</code></pre>
<p>If it were the <code>invert</code> button, we would simply "invert" the output result by multiplying it by "-1."</p>
<pre><code class="lang-js"><span class="hljs-keyword">case</span> <span class="hljs-string">"invert"</span>:
  output.value = <span class="hljs-built_in">parseFloat</span>(output.value) * <span class="hljs-number">-1</span>;
  <span class="hljs-keyword">break</span>;
</code></pre>
<p>If the <code>=</code> button was clicked, we add the last value from the output value to our equation array, use <code>eval()</code> to quickly evaluate every equation there, and then clear the equation array.</p>
<pre><code class="lang-js"><span class="hljs-keyword">case</span> <span class="hljs-string">"="</span>:
  equation.push(output.value);
  output.value = <span class="hljs-built_in">eval</span>(equation.join(<span class="hljs-string">""</span>));
  equation = [];
  <span class="hljs-keyword">break</span>;
</code></pre>
<p>NOTE: <code>eval()</code> is a dangerous function. It can execute code when passed as input, and users can use it to write malicious code that can be dangerous. Only use ever when you trust the source of input that will be provided.</p>
<p>The code in the default runs when any other operator button that is not one of those we listed before is clicked. In the default first, we obtain the last item in the array by using this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> last_item = equation[equation.length - <span class="hljs-number">1</span>];
</code></pre>
<p>Then, if the previous button we clicked was an operator—that is, if it was one of the following: <code>/</code>, <code>*</code>, <code>+</code>, or <code>-</code> —we simply delete it from the equation using <code>equation.pop()</code> and add the new one we clicked with <code>equation.push()</code>.</p>
<p>If our last array item was not an operator, we add the output value and the value of the button we clicked to the equation array.</p>
<pre><code class="lang-js"><span class="hljs-keyword">else</span> {
  equation.push(output.value);
  equation.push(e.target.value);
}
</code></pre>
<p>Lastly we also set the value of <code>is_operator</code> to true anytime we click on any <code>operator</code> button:</p>
<pre><code class="lang-js"><span class="hljs-keyword">default</span>:
  <span class="hljs-keyword">let</span> last_item = equation[equation.length - <span class="hljs-number">1</span>];
  <span class="hljs-keyword">if</span> ([<span class="hljs-string">"/"</span>, <span class="hljs-string">"*"</span>, <span class="hljs-string">"+"</span>, <span class="hljs-string">"-"</span>].includes(last_item) &amp;&amp; is_operator) {
    equation.pop();
    equation.push(e.target.value);
  } <span class="hljs-keyword">else</span> {
    equation.push(output.value);
    equation.push(e.target.value);
  }
  is_operator = <span class="hljs-literal">true</span>;
  <span class="hljs-keyword">break</span>;
</code></pre>
<p>You'll notice that for each case we pass in the <code>break</code> statement. The <code>break</code> statement here will stop the execution of the switch anytime a case is true and the code finishes executing.</p>
<p>And there you have it – a fully functional calculator application! And here's the live preview:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/freeCodeCamp/embed/ZEjyWeE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>Before we finish, there is one little issue with our calculator: the <code>active</code> class we added to our operator buttons when clicked remains active even after we click another button.</p>
<p>Let's remedy that by creating a function that removes the active from any operator button.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> remove_active = <span class="hljs-function">() =&gt;</span> {
  operator_btns.forEach(<span class="hljs-function">(<span class="hljs-params">btn</span>) =&gt;</span> {
    btn.classList.remove(<span class="hljs-string">"active"</span>);
  });
};
</code></pre>
<p>Now we simply need to call this function before adding the active class to any button.</p>
<pre><code class="lang-js">operator_btns.forEach(<span class="hljs-function">(<span class="hljs-params">btn</span>) =&gt;</span> {
  btn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    remove_active();
    e.currentTarget.classList.add(<span class="hljs-string">"active"</span>);
    ...
  });
});
</code></pre>
<p>We also need to remove the active class from the operators whenever an operand button get's clicked.</p>
<pre><code class="lang-js">operand_btns.forEach(<span class="hljs-function">(<span class="hljs-params">btn</span>) =&gt;</span> {
  btn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    remove_active();
    ...
  });
});
</code></pre>
<p>Now that's much better. You can find the full code and live preview of our app in the pen below:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/freeCodeCamp/embed/rNrweyV" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<h3 id="heading-javascript-challenge">JavaScript Challenge</h3>
<p>Despite the fact that our calculator app is now completely working, there are a few functionalities that I did not include that I believe would be a wonderful opportunity for you to practice your new JavaScript skills.</p>
<ul>
<li><p>The clear button: When we click on any operand button, the value of the button should change from AC to C. When this button is clicked, we clear the form and remove any active class from our operator buttons.</p>
</li>
<li><p>The iPhone calculator only allows a maximum of 9 numbers as operands. You cannot surpass this limit, which I believe would be a useful feature for our calculator software as well.</p>
</li>
<li><p>Commas are automatically appended to numbers in the output of the iPhone calculator, and our program does not currently have this capability.</p>
</li>
<li><p>If we use two decimal operands, sometimes the result is affected by a floating point rounding error. Our calculator app is not handling any rounding at the moment. Check out <a target="_blank" href="https://0.30000000000000004.com/">this article</a> if you want to learn more about this topic.</p>
</li>
</ul>
<p>Do you believe you can complete any of these challenges? Good luck!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Congratulations, JavaScript whiz! You've made it this far. In this tutorial, we learnt about the DOM, Loops, JavaScript Events and how to handle them, and we built a simple calculator at the end.</p>
<p>If you participate in the challenge in this post, please share your solution online and tag me <a target="_blank" href="https://twitter.com/sprucekhalifa">@sprucekhalifa</a> on Twitter. And don't forget to follow me as well, as I tweet about JavaScript.</p>
<p>Oh, and happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
