<?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[ Franklin Ohaegbulam - 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[ Franklin Ohaegbulam - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 18 Jun 2026 05:24:26 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/frankiefab100/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Countdown Timer with React – A Step-by-Step Guide ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, you will learn how to build a custom countdown timer to track events using React.js. A countdown timer is a simple way to measure the time until an event happens. It counts down that time in reverse – like 5, 4, 3, 2, 1. It helps yo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-countdown-timer-with-react-step-by-step/</link>
                <guid isPermaLink="false">670d1eef6f6de348bb7f216b</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ReactHooks ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Franklin Ohaegbulam ]]>
                </dc:creator>
                <pubDate>Mon, 14 Oct 2024 13:38:55 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724788718279/35a8ba3c-db35-49b6-ae41-14bcda547795.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, you will learn how to build a custom countdown timer to track events using React.js.</p>
<p>A countdown timer is a simple way to measure the time until an event happens. It counts down that time in reverse – like 5, 4, 3, 2, 1. It helps you manage the time leading up to upcoming events, product launches, or offers, and allows you to inform users about that timeline.</p>
<h3 id="heading-table-of-contents">Table of Contents</h3>
<ul>
<li><p><a class="post-section-overview" href="#heading-1-set-up-your-react-app">1. Set Up Your React App</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-2-create-the-count-down-component">2. Create the Count Down Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-3-implement-time-state-management-and-functionality">3. Implement Time State Management and Functionality</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-4-create-a-countdown-form">4. Create a Countdown Form</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-5-handle-the-countdown-start-stop-and-reset-functionality">5. Handle the Countdown Start, Stop, and Reset Functionality</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-6-format-the-event-date-and-time">6. Format the Event Date and Time</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-7-display-the-countdown-timer">7. Display the CountDown Timer</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-8-styling-the-countdown-timer-component">8. Styling the Countdown Timer Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>You should have decent knowledge of HTML, CSS, and JavaScript to get the most out of this article.</p>
<p>Let's get started.</p>
<h2 id="heading-1-set-up-your-react-app">1. Set Up Your React App</h2>
<p>First, you’ll need to <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-a-react-app-different-ways/#heading-what-is-vite">create a React application</a> if you don’t already have one ready to use. In this tutorial, I’m using Vite. Then change into the new project directory by running the following commands in your code editor:</p>
<pre><code class="lang-bash">npm create vite countdown-timer

<span class="hljs-built_in">cd</span> countdown-timer
</code></pre>
<p>Run this command to start the app on the local server:</p>
<pre><code class="lang-bash">npm run dev
</code></pre>
<p>Now, you should see the project in your browser on <code>https://localhost/3000</code>.</p>
<h2 id="heading-2-create-the-count-down-component">2. Create the Count Down Component</h2>
<p>In the <code>src</code> folder of your React app, create a <code>components</code> directory, and inside it, create a <code>CountDown.jsx</code> file.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

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

<span class="hljs-keyword">const</span> CountdownTImer = <span class="hljs-function">() =&gt;</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">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<h2 id="heading-3-implement-time-state-management-and-functionality">3. Implement Time State Management and Functionality</h2>
<p>Define the state variables using the useState hook. Update the <code>CountDown.jsx</code> file with the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> CountdownTimer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [eventName, setEventName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [eventDate, setEventDate] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [countdownStarted, setCountdownStarted] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [timeRemaining, setTimeRemaining] = useState(<span class="hljs-number">0</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">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<p>Here's a brief breakdown of the <code>useState</code>:</p>
<ul>
<li><p><code>eventName</code>: stores the name of the event for the countdown timer.</p>
</li>
<li><p><code>eventDate</code>: stores the date of the event for the countdown timer.</p>
</li>
<li><p><code>countdownStarted</code>: tracks whether the countdown timer has started.</p>
</li>
<li><p><code>timeRemaining</code>: stores the remaining time in milliseconds for the countdown.</p>
</li>
</ul>
<p>Now, we’ll implement the functionality of the countdown timer using the useEffect hook:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> CountdownTimer = <span class="hljs-function">() =&gt;</span> {

    <span class="hljs-comment">// ...</span>

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (countdownStarted &amp;&amp; eventDate) {
      <span class="hljs-keyword">const</span> countdownInterval = <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> currentTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
        <span class="hljs-keyword">const</span> eventTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(eventDate).getTime();
        <span class="hljs-keyword">let</span> remainingTime = eventTime - currentTime;

        <span class="hljs-keyword">if</span> (remainingTime &lt;= <span class="hljs-number">0</span>) {
          remainingTime = <span class="hljs-number">0</span>;
          <span class="hljs-built_in">clearInterval</span>(countdownInterval);
          alert(<span class="hljs-string">"Countdown complete!"</span>);
        }

        setTimeRemaining(remainingTime);
      }, <span class="hljs-number">1000</span>);

      <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearInterval</span>(countdownInterval);
    }
  }, [countdownStarted, eventDate, timeRemaining]);

 <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">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<p>The <code>useEffect</code> hook runs whenever <code>countdownStarted</code> or <code>eventDate</code> changes. It sets up an interval that updates <code>timeRemaining</code> every second based on the current time and event time. If the remaining time becomes less than or equal to 0, it stops the interval and triggers the notification "Countdown complete!"</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> CountdownTimer = <span class="hljs-function">() =&gt;</span> {

  <span class="hljs-comment">// ...</span>

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (countdownStarted) {
      <span class="hljs-built_in">document</span>.title = eventName;
    }
  }, [countdownStarted, eventName]);

 <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">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<p>Here, the <code>useEffect</code> hook runs whenever <code>countdownStarted</code> or <code>eventName</code> changes. It updates the countdown timer title to display the <code>eventName</code> when the countdown timer is started.</p>
<h2 id="heading-4-create-a-countdown-form">4. Create a Countdown Form</h2>
<p>To have control over the countdown timer, you’ll need to create a form with two inputs for the name and date of the event. Then, add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

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

 <span class="hljs-comment">// ...</span>

   <span class="hljs-keyword">const</span> handleSetCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">true</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">"countdown-timer-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-name"</span>&gt;</span>
        {countdownStarted ? eventName : "Countdown Timer"}
      <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

      {!countdownStarted ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-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">"title"</span>&gt;</span>Event 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">name</span>=<span class="hljs-string">"title"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter event name"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{eventName}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEventName(e.target.value)}
          /&gt;

          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"date-picker"</span>&gt;</span>Event Date<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">name</span>=<span class="hljs-string">"date-picker"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{eventDate}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEventDate(e.target.value)}
            onClick={(e) =&gt; (e.target.type = "date")}
          /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSetCountdown}</span>&gt;</span>Start Countdown<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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> CountdownTimer;
</code></pre>
<p>Here's a brief breakdown of the <code>useState</code>:</p>
<ul>
<li><p><code>eventName</code>: stores the name of the event for the countdown timer.</p>
</li>
<li><p><code>countdown-name</code>: displays the "Countdown Timer" by default or updates to the  <code>eventName</code> entered once the countdown has started.</p>
</li>
</ul>
<p>The form includes:</p>
<ul>
<li><p>The input field with the name <code>title</code> and label <code>Event Name</code> update the <code>eventName</code> state value.</p>
</li>
<li><p>The input field with the name <code>date-picker</code> allow users to select a date and control the  <code>eventDate</code> state value.</p>
</li>
<li><p>The button <code>Start Countdown</code> triggers the <code>handleSetCountdown</code> function when clicked to initiate the countdown.</p>
</li>
</ul>
<h2 id="heading-5-handle-the-countdown-start-stop-and-reset-functionality">5. Handle the Countdown Start, Stop, and Reset Functionality</h2>
<p>Next, update the <code>handleSetCountdown</code> function to store the event name and date in the local storage using <code>localStorage.setItem</code>. localStorage is a web API that enables users to store data as key-value pairs persistently, even when the browser is closed or refreshed.</p>
<p>The code is as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

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

 <span class="hljs-comment">// ...</span>

    <span class="hljs-keyword">const</span> handleSetCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">true</span>);
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"eventDate"</span>, eventDate);
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"eventName"</span>, eventName);
  };

 <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">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<p>Now, create the <code>handleStopCountdown</code> and <code>handleResetCountdown</code> functions to stop the countdown timer by updating the <code>countdownStarted</code> state to <code>false</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

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

 <span class="hljs-comment">// ...</span>

  <span class="hljs-keyword">const</span> handleStopCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">false</span>);
    setTimeRemaining(<span class="hljs-number">0</span>);
  };

  <span class="hljs-keyword">const</span> handleResetCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">false</span>);
    setEventDate(<span class="hljs-string">""</span>);
    setEventName(<span class="hljs-string">""</span>);
    setTimeRemaining(<span class="hljs-number">0</span>);
    <span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">"eventDate"</span>);
    <span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">"eventName"</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">"countdown-timer-container"</span>&gt;</span>
       // ...
       <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"control-buttons"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleStopCountdown}</span>&gt;</span>Stop<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">onClick</span>=<span class="hljs-string">{handleResetCountdown}</span>&gt;</span>Reset<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>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> CountdownTimer;
</code></pre>
<p>Here:</p>
<ul>
<li><p><code>handleStopCountdown</code>: resets the <code>timeRemaining</code> state to zero.</p>
</li>
<li><p><code>handleResetCountdown</code>: resets the countdown timer to its initial state. It clears the remaining time states and removes the event date and event name from local storage using <code>localStorage.removeItem()</code>.</p>
</li>
</ul>
<h2 id="heading-6-format-the-event-date-and-time">6. Format the Event Date and Time</h2>
<p>Let's convert date and time data into a readable format.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* components/CountDown.jsx */</span>

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

 <span class="hljs-comment">// ...</span>

  <span class="hljs-keyword">const</span> formatDate = <span class="hljs-function">(<span class="hljs-params">date</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> options = { <span class="hljs-attr">month</span>: <span class="hljs-string">"long"</span>, <span class="hljs-attr">day</span>: <span class="hljs-string">"numeric"</span>, <span class="hljs-attr">year</span>: <span class="hljs-string">"numeric"</span> };
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date).toLocaleDateString(<span class="hljs-string">"en-US"</span>, options);
  };

  <span class="hljs-keyword">const</span> formatTime = <span class="hljs-function">(<span class="hljs-params">time</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> seconds = <span class="hljs-built_in">Math</span>.floor((time / <span class="hljs-number">1000</span>) % <span class="hljs-number">60</span>);
    <span class="hljs-keyword">const</span> minutes = <span class="hljs-built_in">Math</span>.floor((time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span>)) % <span class="hljs-number">60</span>);
    <span class="hljs-keyword">const</span> hours = <span class="hljs-built_in">Math</span>.floor((time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>)) % <span class="hljs-number">24</span>);
    <span class="hljs-keyword">const</span> days = <span class="hljs-built_in">Math</span>.floor(time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">24</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">"countdown-display"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-value"</span>&gt;</span>
          {days.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>days<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">className</span>=<span class="hljs-string">"countdown-value"</span>&gt;</span>
          {hours.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> hours<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">className</span>=<span class="hljs-string">"countdown-value"</span>&gt;</span>
          {minutes.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>minutes<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">className</span>=<span class="hljs-string">"countdown-value"</span>&gt;</span>
          {seconds.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>seconds<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">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">"countdown-timer-container"</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> CountdownTimer;
</code></pre>
<p>Here's a brief breakdown of the functions:</p>
<ul>
<li><p><code>formatDate</code>: formats the date input into a human-readable date string.</p>
</li>
<li><p><code>formatTime</code>: takes a time in milliseconds as input and calculates the days, hours, minutes, and seconds of the timer. The <code>.toString().padStart(2, "0")</code> returns the formatted time as two characters by appending 0 at the beginning of the time only if the length of the number is less than 2.</p>
</li>
</ul>
<p>Here are the complete contents of the <code>CountDown.jsx</code> file:</p>
<pre><code class="lang-javascript"> <span class="hljs-comment">/* components/CountDown.jsx */</span>

<span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> CountdownTimer = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [eventName, setEventName] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [eventDate, setEventDate] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [countdownStarted, setCountdownStarted] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [timeRemaining, setTimeRemaining] = useState(<span class="hljs-number">0</span>);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (countdownStarted &amp;&amp; eventDate) {
      <span class="hljs-keyword">const</span> countdownInterval = <span class="hljs-built_in">setInterval</span>(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> currentTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
        <span class="hljs-keyword">const</span> eventTime = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(eventDate).getTime();
        <span class="hljs-keyword">let</span> remainingTime = eventTime - currentTime;

        <span class="hljs-keyword">if</span> (remainingTime &lt;= <span class="hljs-number">0</span>) {
          remainingTime = <span class="hljs-number">0</span>;
          <span class="hljs-built_in">clearInterval</span>(countdownInterval);
          alert(<span class="hljs-string">"Countdown complete!"</span>);
        }

        setTimeRemaining(remainingTime);
      }, <span class="hljs-number">1000</span>);

      <span class="hljs-keyword">return</span> <span class="hljs-function">() =&gt;</span> <span class="hljs-built_in">clearInterval</span>(countdownInterval);
    }
  }, [countdownStarted, eventDate, timeRemaining]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (countdownStarted) {
      <span class="hljs-built_in">document</span>.title = eventName;
    }
  }, [countdownStarted, eventName]);

  <span class="hljs-keyword">const</span> handleSetCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">true</span>);
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"eventDate"</span>, eventDate);
    <span class="hljs-built_in">localStorage</span>.setItem(<span class="hljs-string">"eventName"</span>, eventName);
  };

  <span class="hljs-keyword">const</span> handleStopCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">false</span>);
    setTimeRemaining(<span class="hljs-number">0</span>);
  };

  <span class="hljs-keyword">const</span> handleResetCountdown = <span class="hljs-function">() =&gt;</span> {
    setCountdownStarted(<span class="hljs-literal">false</span>);
    setEventDate(<span class="hljs-string">""</span>);
    setEventName(<span class="hljs-string">""</span>);
    setTimeRemaining(<span class="hljs-number">0</span>);
    <span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">"eventDate"</span>);
    <span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">"eventName"</span>);
  };

  <span class="hljs-keyword">const</span> formatDate = <span class="hljs-function">(<span class="hljs-params">date</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> options = { <span class="hljs-attr">month</span>: <span class="hljs-string">"long"</span>, <span class="hljs-attr">day</span>: <span class="hljs-string">"numeric"</span>, <span class="hljs-attr">year</span>: <span class="hljs-string">"numeric"</span> };
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(date).toLocaleDateString(<span class="hljs-string">"en-US"</span>, options);
  };

  <span class="hljs-keyword">const</span> formatTime = <span class="hljs-function">(<span class="hljs-params">time</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> seconds = <span class="hljs-built_in">Math</span>.floor((time / <span class="hljs-number">1000</span>) % <span class="hljs-number">60</span>);
    <span class="hljs-keyword">const</span> minutes = <span class="hljs-built_in">Math</span>.floor((time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span>)) % <span class="hljs-number">60</span>);
    <span class="hljs-keyword">const</span> hours = <span class="hljs-built_in">Math</span>.floor((time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>)) % <span class="hljs-number">24</span>);
    <span class="hljs-keyword">const</span> days = <span class="hljs-built_in">Math</span>.floor(time / (<span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">24</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">"countdown-display"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-value"</span>&gt;</span>
          {days.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>days<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">className</span>=<span class="hljs-string">"countdown-value"</span>&gt;</span>
          {hours.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span> hours<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">className</span>=<span class="hljs-string">"countdown-value"</span>&gt;</span>
          {minutes.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>minutes<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">className</span>=<span class="hljs-string">"countdown-value"</span>&gt;</span>
          {seconds.toString().padStart(2, "0")} <span class="hljs-tag">&lt;<span class="hljs-name">span</span>&gt;</span>seconds<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">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">"countdown-timer-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-name"</span>&gt;</span>
        {countdownStarted ? eventName : "Countdown Timer"}
      <span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-date"</span>&gt;</span>
        {countdownStarted &amp;&amp; formatDate(eventDate)}
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>

      {!countdownStarted ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"countdown-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">"title"</span>&gt;</span>Event 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">name</span>=<span class="hljs-string">"title"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter event name"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{eventName}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEventName(e.target.value)}
          /&gt;

          <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"date-picker"</span>&gt;</span>Event Date<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">name</span>=<span class="hljs-string">"date-picker"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{eventDate}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setEventDate(e.target.value)}
            onClick={(e) =&gt; (e.target.type = "date")}
          /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleSetCountdown}</span>&gt;</span>Start Countdown<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;&gt;</span>
          {formatTime(timeRemaining)}
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"control-buttons"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleStopCountdown}</span>&gt;</span>Stop<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">onClick</span>=<span class="hljs-string">{handleResetCountdown}</span>&gt;</span>Reset<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;/div&gt;
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> CountdownTimer;
</code></pre>
<h2 id="heading-7-display-the-countdown-timer">7. Display the CountDown Timer</h2>
<p>Import <code>CountDownTimer</code> in the <code>App.jsx</code>, replacing the default code with this:</p>
<pre><code class="lang-javascript"> <span class="hljs-comment">/* App.jsx */</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> CountdownTimer <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/CountDown"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</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">"App"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">CountdownTimer</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> App;
</code></pre>
<p>And that's it! Your countdown timer app should be rendered on  <code>localhost:3000</code> in the browser.</p>
<h2 id="heading-8-styling-the-countdown-timer-component">8. Styling the Countdown Timer Component</h2>
<p>Lastly, update the <code>index.css</code> file in the same directory of your project by adding the following styles:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> url(<span class="hljs-string">"https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&amp;family=Open+Sans:wght@400;500;700&amp;display=swap"</span>);

* {
  <span class="hljs-attribute">box-sizing</span>: border-box;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">background</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"./img/bg-img.jpg"</span>) top center;
  <span class="hljs-attribute">background-size</span>: cover;
  <span class="hljs-attribute">background-repeat</span>: no-repeat;
  <span class="hljs-attribute">background-attachment</span>: fixed;
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Inter"</span>, sans-serif;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</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">flex-direction</span>: column;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
}

<span class="hljs-selector-class">.countdown-form</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f6f6f6</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1.5rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">12px</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-selector-tag">label</span> {
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
}

<span class="hljs-selector-tag">input</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#d1f1ee</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#dfdfdf</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">outline</span>: none;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.75rem</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">transition</span>: border-color <span class="hljs-number">0.2s</span> ease;
}

<span class="hljs-selector-tag">input</span><span class="hljs-selector-pseudo">:focus</span> {
  <span class="hljs-attribute">border-color</span>: <span class="hljs-number">#038a7f</span>;
}

<span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#038a7f</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">6px</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">outline</span>: none;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">text-transform</span>: uppercase;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">2.75rem</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
  <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">0.5px</span>;
  <span class="hljs-attribute">transition</span>: background-color <span class="hljs-number">0.2s</span> ease;
}

<span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#005a53</span>;
}

<span class="hljs-selector-class">.countdown-message</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">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.25rem</span>, <span class="hljs-number">4vw</span>, <span class="hljs-number">1.5rem</span>);
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">1rem</span> <span class="hljs-number">0</span>;
}

<span class="hljs-selector-class">.countdown-name</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.5rem</span>, <span class="hljs-number">5vw</span>, <span class="hljs-number">2rem</span>);
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">text-shadow</span>: <span class="hljs-number">2px</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.3</span>);
}

<span class="hljs-selector-class">.countdown-date</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#eafbfa</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1.5rem</span>;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1rem</span>, <span class="hljs-number">3vw</span>, <span class="hljs-number">1.25rem</span>);
  <span class="hljs-attribute">text-shadow</span>: <span class="hljs-number">2px</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.3</span>);
}

<span class="hljs-selector-class">.countdown-display</span> {
  <span class="hljs-attribute">display</span>: grid;
  <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(auto-fit, minmax(<span class="hljs-number">80px</span>, <span class="hljs-number">1</span>fr));
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">600px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
}

<span class="hljs-selector-class">.countdown-value</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#2f5d6f</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#03d5c0</span>;
  <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">1</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">justify-content</span>: center;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.5rem</span>, <span class="hljs-number">5vw</span>, <span class="hljs-number">2.5rem</span>);
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">700</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.2</span>);
  <span class="hljs-attribute">transition</span>: transform <span class="hljs-number">0.2s</span> ease;
}

<span class="hljs-selector-class">.countdown-value</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1.05</span>);
}

<span class="hljs-selector-class">.countdown-value</span> &gt; <span class="hljs-selector-tag">span</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">0.75rem</span>, <span class="hljs-number">2vw</span>, <span class="hljs-number">0.875rem</span>);
  <span class="hljs-attribute">letter-spacing</span>: <span class="hljs-number">1px</span>;
  <span class="hljs-attribute">text-transform</span>: uppercase;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">0.2rem</span>;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">500</span>;
}

<span class="hljs-selector-class">.control-buttons</span> {
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">flex-wrap</span>: wrap;
}

<span class="hljs-selector-class">.control-buttons</span> &gt; <span class="hljs-selector-tag">button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#03b4a2</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">45px</span>, <span class="hljs-number">8vw</span>, <span class="hljs-number">50px</span>);
  <span class="hljs-attribute">height</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">45px</span>, <span class="hljs-number">8vw</span>, <span class="hljs-number">50px</span>);
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</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-built_in">clamp</span>(<span class="hljs-number">0.65rem</span>, <span class="hljs-number">2vw</span>, <span class="hljs-number">0.775rem</span>);
}

<span class="hljs-selector-class">.control-buttons</span> <span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0b7c71</span>;
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">scale</span>(<span class="hljs-number">1.1</span>);
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">480px</span>) {
  <span class="hljs-selector-class">.countdown-display</span> {
    <span class="hljs-attribute">grid-template-columns</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">2</span>, <span class="hljs-number">1</span>fr);
    <span class="hljs-attribute">gap</span>: <span class="hljs-number">0.75rem</span>;
  }

  <span class="hljs-selector-class">.countdown-value</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">clamp</span>(<span class="hljs-number">1.25rem</span>, <span class="hljs-number">4vw</span>, <span class="hljs-number">1.75rem</span>);
  }

  <span class="hljs-selector-class">.countdown-value</span> &gt; <span class="hljs-selector-tag">span</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">0.75rem</span>;
  }

  <span class="hljs-selector-class">.control-buttons</span> {
    <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1.5rem</span>;
  }
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">max-width:</span> <span class="hljs-number">360px</span>) {
  <span class="hljs-selector-tag">body</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.75rem</span>;
  }

  <span class="hljs-selector-class">.countdown-form</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
  }

  <span class="hljs-selector-class">.countdown-name</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.25rem</span>;
  }

  <span class="hljs-selector-class">.countdown-date</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  }

  <span class="hljs-selector-class">.control-buttons</span> &gt; <span class="hljs-selector-tag">button</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-number">40px</span>;
    <span class="hljs-attribute">height</span>: <span class="hljs-number">40px</span>;
  }
}
</code></pre>
<p>Congratulations, you’ve finished building your Countdown timer app!</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you've learned how to build a basic React countdown timer app and how to work with the browser's local storage.</p>
<p>The code implemented in this article is accessible in this <a target="_blank" href="https://github.com/frankiefab100/countdown-timer">GitHub repository</a>. To learn more about web development and technology, check out my <a target="_blank" href="https://frankiefab.hashnode.dev/">blog</a> or connect with me on <a target="_blank" href="https://twitter.com/frankiefab100">X(Twitter)</a> and <a target="_blank" href="https://linkedin.com/in/frankiefab100/">LinkedIn</a>.</p>
<p>Thank you for reading.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Hide API Keys in Frontend Apps using Netlify Functions ]]>
                </title>
                <description>
                    <![CDATA[ Netlify is a popular web development platform that makes it easier to build, deploy, and manage websites. You can use Netlify to host websites, and it helps you update and release new changes. It also provides additional features such as security, us... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/hide-api-keys-in-frontend-apps-using-netlify-functions/</link>
                <guid isPermaLink="false">66d45edbd1ffc3d3eb89ddd7</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lambda ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Netlify ]]>
                    </category>
                
                    <category>
                        <![CDATA[ netlify-functions ]]>
                    </category>
                
                    <category>
                        <![CDATA[ serverless ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Franklin Ohaegbulam ]]>
                </dc:creator>
                <pubDate>Tue, 07 Feb 2023 23:46:43 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/02/FCC-hide-API-keys-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Netlify is a popular web development platform that makes it easier to build, deploy, and manage websites.</p>
<p>You can use Netlify to host websites, and it helps you update and release new changes. It also provides additional features such as security, user authentication and authorization services, and more.</p>
<p>This guide focuses on showing you how to set up a Netlify serverless function to hide Application Programming Interface (API) keys in a client-side application.</p>
<p>For this lesson, you will create a stock photo search engine web application, deploy it on Netlify, and make an API call to the Pixabay API using Netlify serverless functions.</p>
<p>This is the same process for front-end applications built with ReactJS, NextJS, VueJS, Angular, or other JavaScript frameworks.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>To follow along with this tutorial, you should have the following:</p>
<ul>
<li><p>Netlify account (you can sign up <a target="_blank" href="http://netlify.com">here</a>)</p>
</li>
<li><p>Basic understanding of RESTful APIs, Lambda functions, and async/await concepts.</p>
</li>
</ul>
<p>The final demo app lives in the main branch on GitHub: <code>https://netlify-func-demo.netlify.app</code></p>
<h2 id="heading-what-is-a-netlify-function">What is a Netlify function?</h2>
<p>Netlify functions are serverless or lambda functions provided by Netlify. You use them to deploy server-side code or backend logic without the need for a dedicated server.</p>
<p>The purpose of this Netlify function is to manage serverless event-driven code and send HTTP requests that return a JSON response.</p>
<blockquote>
<p>"Serverless functions, branded as Netlify Functions when running on Netlify, are a way to deploy server-side code as API endpoints" - Netlify Docs</p>
</blockquote>
<p>It securely accesses environment variables behind the scenes via the Amazon Web Services (AWS) lambda function.</p>
<p>Secret credentials such as access tokens or API keys, hidden solely using environment variables, are less secure. This is because they can be easily retrieved from the Developer Tools through the API fetch request in the browser.</p>
<p>The API keys, if hijacked, can be misused by malicious actors, which might affect your app build threshold or cost you more if it's a paid API service.</p>
<p>Other serverless functions used for running code without having to manage servers include AWS Lambda functions, Azure functions, and Google cloud functions.</p>
<h2 id="heading-how-to-set-up-a-client-side-application">How to Set Up a Client-side Application</h2>
<h3 id="heading-how-to-clone-the-demo-app">How to Clone the Demo App</h3>
<p>To get started with this tutorial, you can clone the <strong>stock photo search engine app</strong> <a target="_blank" href="https://github.com/frankiefab100/netlify-serverless-functions-demo/tree/main">GitHub repository</a>. See the live preview on Netlify at <a target="_blank" href="https://netlify-func-demo.netlify.app">https://netlify-func-demo.netlify.app</a>.</p>
<p>The first step is to clone the repository:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/frankiefab100/netlify-serverless-functions-demo.git
</code></pre>
<p>Next, change to the <strong>netlify-serverless-functions-demo</strong> directory.</p>
<pre><code class="lang-bash"> <span class="hljs-built_in">cd</span> netlify-serverless-functions-demo
</code></pre>
<p>Then you'll need to install dependencies.</p>
<pre><code class="lang-bash">npm install
<span class="hljs-comment">#OR </span>
yarn add
</code></pre>
<p>Now run the development server. Run the following command to start the app on the server:</p>
<pre><code class="lang-bash">netlify dev
</code></pre>
<p>The app will be ready on <code>https://localhost:8888</code>.</p>
<p>Alternatively, you can skip the above steps if you wish to follow along by building the app from scratch. In the next step, you will build a stock photo search engine JavaScript application.</p>
<h3 id="heading-how-to-build-the-demo-app-using-javascript">How to Build the Demo App using JavaScript</h3>
<p>The first step is to set up a front-end app. Open your favorite code editor, such as VS Code.</p>
<p>Then, create a <strong>dist</strong> directory and inside it create an <strong>index.html</strong> file. Populate it with the following code:</p>
<pre><code class="lang-xml"><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">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">title</span>&gt;</span>Stock Photos Search Engine<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">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">header</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Search For Stock Photos<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"search-section"</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">"search"</span>
            <span class="hljs-attr">class</span>=<span class="hljs-string">"search"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter a keyword"</span>
          /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
            <span class="hljs-attr">id</span>=<span class="hljs-string">"searchBtn"</span>
            <span class="hljs-attr">class</span>=<span class="hljs-string">"search-btn"</span>
            <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">"Search"</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">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"photo-wrapper"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">""</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">""</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"photo"</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">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"./script.js"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"module"</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>In the same <code>dist</code> directory, add the following styling to style.css:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* dist/style.css */</span>
* {
  <span class="hljs-attribute">box-sizing</span>: border-box;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
}

<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#222</span>;
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">"Roboto"</span>, sans-serif;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100vw</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
}

<span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">min-width</span>: <span class="hljs-number">100vw</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100%</span>;
}

<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-selector-class">.search-section</span> {
  <span class="hljs-attribute">display</span>: inline;
  <span class="hljs-attribute">text-align</span>: center;
  <span class="hljs-attribute">min-width</span>: <span class="hljs-number">310px</span>;
}

<span class="hljs-selector-class">.search</span>,
<span class="hljs-selector-class">.search-btn</span> {
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">50px</span>;
}

<span class="hljs-selector-class">.search</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#d1f3bf</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#222</span>;
  <span class="hljs-attribute">min-width</span>: <span class="hljs-number">225px</span>;
}

<span class="hljs-selector-class">.search-btn</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#04ab04</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#f6f6f6</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
  <span class="hljs-attribute">margin-left</span>: <span class="hljs-number">5px</span>;
  <span class="hljs-attribute">min-width</span>: <span class="hljs-number">80px</span>;
  <span class="hljs-attribute">transition</span>: all <span class="hljs-number">0.3s</span> ease-in-out;
}

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

<span class="hljs-selector-class">.photo-wrapper</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">15px</span>;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">30px</span>;
}

<span class="hljs-selector-class">.photo-wrapper</span> <span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">200px</span>;
}
</code></pre>
<h2 id="heading-sign-up-for-a-free-account-on-pixabay">Sign Up for a Free Account on Pixabay</h2>
<p>The first step to using the <a target="_blank" href="https://pixabay.com/api/docs/">Pixabay API</a> is to sign up for an account with your email.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Pixabay-API-Documentation.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Pixabay API key section</em></p>
<p>As shown in the image above, your API key can be found below the <strong>parameters</strong> section in the <a target="_blank" href="https://pixabay.com/api/docs/">Pixabay API Docs website</a>.</p>
<h3 id="heading-create-an-environment-variable">Create an environment variable</h3>
<p>Environment variables (commonly known as "env") are combinations of key/value pairs that can affect the behavior and processes of an operating system or application.</p>
<p>Using environment variables is recommended to configure third-party services and their credentials during development.</p>
<h3 id="heading-install-dotenv">Install dotenv</h3>
<p>Once you complete the account creation on Pixabay, open your terminal and install <strong>dotenv</strong> as a package. This will enable your app to read environment variables saved in the <strong>.env</strong> file.</p>
<pre><code class="lang-javascript">npm install dotenv
#OR
yarn add -D dotenv
</code></pre>
<p>In the next step, you will save the API key in a <strong>.env</strong> file.</p>
<h3 id="heading-create-the-env-file">Create the .env file</h3>
<p>In the root directory of your app, create a <strong>.env</strong> file and store the API keys copied from your Pixabay Profile.</p>
<pre><code class="lang-plaintext">PIXABAY_API_KEY=123456-7890
</code></pre>
<p>Where <code>PIXABAY_API_KEY=123456-7890</code> represents the API key value.</p>
<p><strong>Note:</strong> Replace this key/value pair with the appropriate value.</p>
<h3 id="heading-create-a-gitignore-file">Create a .gitignore file</h3>
<p>To avoid committing sensitive files and values such as <code>node_modules</code> and <code>secret keys</code> to a public repository, create a <strong>.gitignore</strong> file in the same project root directory and add the following to it:</p>
<pre><code class="lang-plaintext">node_modules
.env
.netlify
</code></pre>
<p>The <strong>.netlify</strong> folder which contains compiled serverless functions together with other files listed will be excluded when the project is pushed to GitHub or any other version control system.</p>
<h3 id="heading-create-a-get-request-function">Create a get request function</h3>
<p>Now, you should add the fetch request logic in the <strong>script.js</strong>. You will adjust the API logic later using Netlify functions.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* dist/script.js */</span>
<span class="hljs-keyword">const</span> dotenv = <span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();

<span class="hljs-keyword">const</span> searchbar = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".search"</span>);
<span class="hljs-keyword">const</span> submitBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".search-btn"</span>);
<span class="hljs-keyword">const</span> photoWrapper = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".photo-wrapper"</span>);

submitBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> {
  getPhoto(searchbar.value);
  searchbar.value = <span class="hljs-string">""</span>;
});

<span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"keydown"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (e.keyCode === <span class="hljs-number">13</span>) {
    getPhoto(searchbar.value);
    searchbar.value = <span class="hljs-string">""</span>;
  }
});

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPhoto</span>(<span class="hljs-params">keyword</span>) </span>{
  <span class="hljs-keyword">const</span> apiKey = PIXABAY_API_KEY;
  <span class="hljs-keyword">let</span> apiURL = <span class="hljs-string">`https://pixabay.com/api/?key=<span class="hljs-subst">${apiKey}</span>&amp;q=<span class="hljs-subst">${keyword}</span>&amp;image_type=photo&amp;safesearch=true&amp;per_page=3`</span>;

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(apiURL, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">headers</span>: { <span class="hljs-attr">accept</span>: <span class="hljs-string">"application/json"</span> },
    });
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();

    <span class="hljs-keyword">let</span> imageURL = data.hits;

    imageURL.forEach(<span class="hljs-function">(<span class="hljs-params">result</span>) =&gt;</span> {
      <span class="hljs-keyword">let</span> imageElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"img"</span>);
      imageElement.setAttribute(<span class="hljs-string">"src"</span>, <span class="hljs-string">`<span class="hljs-subst">${result.webformatURL}</span>`</span>);
      photoWrapper.appendChild(imageElement);
    });
  } <span class="hljs-keyword">catch</span> (error) {
    alert(error);
  }
}
</code></pre>
<p><strong>Note:</strong> As mentioned earlier, if the codebase of this app is published on GitHub. The API key will still be accessible from the client side on a browser, although the <code>.env</code> file that contains the secret key was excluded.</p>
<p>To illustrate this, select the <a target="_blank" href="https://github.com/frankiefab100/netlify-serverless-functions-demo/tree/testing"><code>testing</code> branch</a> of this app repository. The <a target="_blank" href="https://testing--netlify-func-demo.netlify.app/">Live site preview</a> will display the following Reference Errors in your browser console:</p>
<pre><code class="lang-bash">Uncaught ReferenceError: require is not defined
Uncaught ReferenceError: require is not defined at getPhotos
Uncaught ReferenceError: process is not defined at getPhotos
</code></pre>
<p>This is because there is no way to reference the environment variables specified in the <strong>.env</strong> file, since they weren't committed to the public repository on GitHub.</p>
<p>In the next step, select and clone the <code>[testing](https://github.com/frankiefab100/netlify-serverless-functions-demo/tree/testing)</code> branch on your local machine with the following commands:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/frankiefab100/netlify-serverless-functions-demo.git
<span class="hljs-built_in">cd</span> netlify-serveless-functions-demo
npm install
netlify dev
</code></pre>
<p>The app should launch on your browser via <code>localhost:8888</code>.</p>
<p>Now, go to the <strong>Developer tools,</strong> right-click and select <strong>Inspect</strong>. Alternatively, press the <strong>F12</strong> key. Then, navigate to <strong>Network tab</strong> and tab on the <code>getPhotos.js</code> request URL.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--124----Copy.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>API key displayed in the Network tab in Developer tools</em></p>
<p>You should see the API key publicly exposed in the <strong>Network tab</strong>'s <strong>Headers</strong> section and return as a response data in your browser.</p>
<p>This is a security issue since the Network tab in the Developer tools is typically responsible to display informations such as the request URL, response status, and response data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--127----Copy.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>API key returned as a response data and exposed in the URL of the request</em></p>
<p>In the next section, you will find a way to secure the API key using Netlify functions.</p>
<h2 id="heading-how-to-get-started-with-netlify-functions">How to Get Started with Netlify Functions</h2>
<p>First, you'll need to go into your terminal and install <strong>Netlify CLI</strong> and <strong>Lambda</strong> as Devdependencies. You can do that by running this command:</p>
<pre><code class="lang-bash">npm install -g netlify-cli netlify-lambda
<span class="hljs-comment">#OR </span>
yarn add -D netlify-cli netlify-lambda --save-dev
</code></pre>
<h3 id="heading-add-custom-build-and-development-commands-in-packagejson">Add custom build and development commands in package.json</h3>
<p>These commands build and start the app in the server and also launch the app on your web browser. Here's an example of how you might add these script commands in the <strong>package.json</strong> file:</p>
<pre><code class="lang-bash"><span class="hljs-string">"scripts"</span>: {
   <span class="hljs-string">"build"</span>: <span class="hljs-string">"npm run-script"</span>,
   <span class="hljs-string">"dev"</span>: <span class="hljs-string">"netlify dev"</span>
 }
</code></pre>
<h3 id="heading-install-axios">Install Axios</h3>
<p>You will use the <code>axios.get</code> method, because it is a node function unlike the <code>fetch</code> method that is intended for browser runtime.</p>
<p>To install Axios, open your terminal and enter the command:</p>
<pre><code class="lang-bash">npm install axios
<span class="hljs-comment">#OR</span>
yarn add -D axios
</code></pre>
<p>In this case, you are working with a vanilla JavaScript app, so you should import Axios in the <code>getPhotos.js</code> file as:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);
</code></pre>
<p>For JavaScript libraries, like React, import it as follows:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
</code></pre>
<h3 id="heading-create-a-serverless-function">Create a serverless function</h3>
<p>In the root of the project, create a folder named <code>netlify,</code>and inside it create another folder <code>functions</code>. In this <code>functions</code> directory, create a file named <code>getPhotos.js</code>.</p>
<p>You will create a serverless function in the <code>getPhotos</code>. This will completely hide the API keys while fetching images from the <a target="_blank" href="https://pixabay.com/api">Pixabay API</a>.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">//netlify/functions/getPhotos.js </span>
<span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv"</span>).config();

<span class="hljs-keyword">const</span> axios = <span class="hljs-built_in">require</span>(<span class="hljs-string">"axios"</span>);

<span class="hljs-built_in">exports</span>.handler = <span class="hljs-keyword">async</span> (event, context) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> { keyword } = event.queryStringParameters;
    <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> axios.get(
      <span class="hljs-string">`https://pixabay.com/api/?key=<span class="hljs-subst">${process.env.PIXABAY_API_KEY}</span>&amp;q=<span class="hljs-subst">${keyword}</span>&amp;image_type=photo&amp;safesearch=true&amp;per_page=3`</span>,
      {
        <span class="hljs-attr">headers</span>: { <span class="hljs-attr">Accept</span>: <span class="hljs-string">"application/json"</span>, <span class="hljs-string">"Accept-Encoding"</span>: <span class="hljs-string">"identity"</span> },
        <span class="hljs-attr">params</span>: { <span class="hljs-attr">trophies</span>: <span class="hljs-literal">true</span> },
      }
    );

    <span class="hljs-keyword">let</span> imageURL = response.data.hits;

    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">statusCode</span>: <span class="hljs-number">200</span>,
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ imageURL }),
    };
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">statusCode</span>: <span class="hljs-number">500</span>,
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ error }),
    };
  }
};
</code></pre>
<p>Here, the <code>process.env.PIXABAY_API_KEY</code> references API key environment configuration specified in the <code>.env</code> file for development mode.</p>
<p>The <code>keyword</code> parameter accepts a string accessible in the <code>queryStringParameters</code> property and returns a response data stored in the variable <code>imageURL</code>. This will get passed to the <code>script.js</code> as request response (we'll discuss this later).</p>
<p>If the GET request is successful, it returns a response of <code>statusCode</code> 200 with the corresponding response as a JSON object. For errors, we will get an alert with the error message and status code.</p>
<p>Due to changes in version, Axios might return Buffer as a response in your terminal window, that looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/netlify-data.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Buffer response from Axios in Terminal</em></p>
<p>To prevent this, you should attach the following to the GET request:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">let</span> response = <span class="hljs-keyword">await</span> axios.get(
      <span class="hljs-string">`https://pixabay.com/api/?key=<span class="hljs-subst">${process.env.PIXABAY_API_KEY}</span>&amp;q=<span class="hljs-subst">${keyword}</span>&amp;image_type=photo&amp;safesearch=true&amp;per_page=3`</span>,
      {
        <span class="hljs-attr">headers</span>: { <span class="hljs-attr">Accept</span>: <span class="hljs-string">"application/json"</span>, <span class="hljs-string">"Accept-Encoding"</span>: <span class="hljs-string">"identity"</span> },
        <span class="hljs-attr">params</span>: { <span class="hljs-attr">trophies</span>: <span class="hljs-literal">true</span> },
      }
    );
</code></pre>
<h3 id="heading-create-a-netlify-configuration-file">Create a Netlify configuration file</h3>
<p>In the project root directory, create a <code>netlify.toml</code> file. This file specifies how Netlify builds and deploys your app.</p>
<p>Now, add the following build configurations in <code>netlify.toml</code>:</p>
<pre><code class="lang-bash">[build]
  <span class="hljs-built_in">command</span> = <span class="hljs-string">"npm run build"</span>
  <span class="hljs-built_in">functions</span> = <span class="hljs-string">"netlify/functions"</span>
  publish = <span class="hljs-string">"dist"</span>
</code></pre>
<p><strong>Note:</strong></p>
<ul>
<li><p><code>command = "npm run build"</code> triggers the Netlify CLI to build the app from the functions.</p>
</li>
<li><p><code>functions = "netlify/functions"</code> indicates that the <code>getPhotos</code> functions exist in the <code>netlify/functions</code> directory.</p>
</li>
<li><p><code>publish = "dist"</code> identifies <code>dist</code> as the directory where the file will be served from.</p>
</li>
</ul>
<h3 id="heading-update-the-scriptjs-file-with-the-netlify-functions-request-url">Update the script.js file with the Netlify functions request URL</h3>
<p>Next, update the <code>apiURL</code> from this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> apiURL = <span class="hljs-string">`https://pixabay.com/api/?key=<span class="hljs-subst">${apiKey}</span>&amp;q=<span class="hljs-subst">${keyword}</span>&amp;image_type=photo&amp;safesearch=true&amp;per_page=3`</span>;
</code></pre>
<p>to the functions HTTP request endpoint:</p>
<pre><code class="lang-javascript">  <span class="hljs-keyword">let</span> apiURL = <span class="hljs-string">`/.netlify/functions/getPhotos?keyword=<span class="hljs-subst">${keyword}</span>`</span>;
</code></pre>
<p>This serverless function will get queried to the client-side of your app through the endpoint: <code>/.netlify/functions/getPhotos</code>. Once a fetch request is sent, the <code>getphotos</code> function will be invoked and accessed in the <code>script.js.</code></p>
<p>The <code>getPhotos</code> Netlify functions' response <code>imageURL</code> will be passed and the data accessed as the value of the <code>keyword</code> parameter in the query string of function. It will get loop through to return three images from the Pixabay API to the client-side.</p>
<p>The <strong>script.js</strong> file should look like this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* dist/script.js */</span>
<span class="hljs-keyword">const</span> searchbar = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".search"</span>);
<span class="hljs-keyword">const</span> submitBtn = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".search-btn"</span>);
<span class="hljs-keyword">const</span> photoWrapper = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">".photo-wrapper"</span>);

submitBtn.addEventListener(<span class="hljs-string">"click"</span>, <span class="hljs-function">() =&gt;</span> {
  getPhoto(searchbar.value);
  searchbar.value = <span class="hljs-string">""</span>;
  photoWrapper.innerHTML = <span class="hljs-string">""</span>;
});

<span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"keydown"</span>, <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
  <span class="hljs-keyword">if</span> (e.keyCode === <span class="hljs-number">13</span>) {
    getPhoto(searchbar.value);
    searchbar.value = <span class="hljs-string">""</span>;
    photoWrapper.innerHTML = <span class="hljs-string">""</span>;
  }
});

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getPhoto</span>(<span class="hljs-params">keyword</span>) </span>{
  <span class="hljs-keyword">let</span> apiURL = <span class="hljs-string">`/.netlify/functions/getPhotos?keyword=<span class="hljs-subst">${keyword}</span>`</span>;

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(apiURL, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"GET"</span>,
      <span class="hljs-attr">headers</span>: { <span class="hljs-attr">accept</span>: <span class="hljs-string">"application/json"</span> },
    });
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; data.imageURL.length; i++) {
      <span class="hljs-keyword">let</span> imageElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"img"</span>);
      imageElement.setAttribute(<span class="hljs-string">"src"</span>, <span class="hljs-string">`<span class="hljs-subst">${data.imageURL[i].webformatURL}</span>`</span>);
      photoWrapper.appendChild(imageElement);
    }
  } <span class="hljs-keyword">catch</span> (error) {
    alert(error);
  }
}
</code></pre>
<p><strong>Note:</strong> From the codebase above, your environment variable is secure since it is accessed from the serverless function.</p>
<h3 id="heading-run-the-development-server">Run the development server</h3>
<p>Now, execute your app by running the command:</p>
<pre><code class="lang-bash">netlify dev
</code></pre>
<p>This will load the <strong>getPhotos</strong> function via <code>https://localhost:8888/.netlify/functions/getPhotos.</code></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/netlify-dev-terminal.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>netlify build terminal output</em></p>
<p>Then, start the development server and launch the application in your default web browser on <code>localhost:8888</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/netlify-success2.JPG" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>netlify function ready on https://localhost:8888</em></p>
<p>At this point, the Netlify function is fully setup, and you can now proceed to make <code>GET</code> HTTP requests.</p>
<h3 id="heading-how-to-send-fetch-requests">How to Send Fetch Requests</h3>
<p>Now that you already have the web app served, go ahead and send a fetch request. Enter some text in the search input field and hit <strong>Enter</strong> or click the button to fetch images from the Pixabay API.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Stock-Photos-Search-Engine--1-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>flower images fetched from Pixabay API</em></p>
<p>For more information about the Pixabay API, see the <a target="_blank" href="https://pixabay.com/api/docs">Pixabay documentation</a>.</p>
<p>The preceding command will send a request to the serverless function and then return six responses. Here's what the response looks like in your terminal windows:</p>
<blockquote>
<p>Request from ::1: GET /.netlify/functions/getPhotos?keyword=flower<br>Response with status 200 in 4895 ms.</p>
</blockquote>
<p>You can also use <strong>Developer tools</strong> through the <strong>Network</strong> tab to validate the request.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--118----Copy.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>serverless function API response data</em></p>
<p>The fetch request returns our app URL, the <strong>getPhotos</strong> Netlify function, script.js and the images from Pixabay.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--120-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Netlify function fetch response from Network tab's header section in the browser</em></p>
<h2 id="heading-how-to-host-the-app-on-the-remote-repository">How to Host the App on the Remote Repository</h2>
<p>Now, you should push your project to GitHub version control.</p>
<pre><code class="lang-javascript">git add .
git commit -m<span class="hljs-string">"initial commit"</span>
git push origin -u main
</code></pre>
<h2 id="heading-how-to-deploy-the-app-and-serverless-function-on-netlify">How to Deploy the App and Serverless Function on Netlify</h2>
<p>Once you have published the project on GitHub, log in to <a target="_blank" href="https://app.netlify.com">Netlify</a> and connect your GitHub account by granting authorization.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--130-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Import project for deployment on Netlify</em></p>
<p>As shown in the image above, click the <code>Add A New Project</code> and then search for the app repository from the list. Next, click on <code>Build Your Site</code>. This will take a few minutes to complete.</p>
<p>You just deployed the app from the Netlify UI. Your app is now ready at: <code>https://netlify-func-demo.netlify.app.</code>.</p>
<p>The fetch request URL should look like this: <code>https://netlify-func-demo.netlify.app/.netlify/functions/getPhotos</code>.</p>
<h2 id="heading-optional-how-to-configure-the-netlify-app-from-the-dashboard">Optional - How to Configure the Netlify App from the Dashboard</h2>
<p>Alternatively, you can configure the Netlify command from the Netlify Dashboard. If these settings are already specified in <strong>netlify.toml</strong>, it will override any corresponding configuration.</p>
<p>First, select the project directory's Site settings.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Site-overview-netlify-func-demo1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Site settings for project directory on Netlify</em></p>
<h3 id="heading-set-the-build-command-and-publish-directory">Set the Build command and Publish directory</h3>
<p>Navigate to <code>Site settings</code> &gt; <code>Deploy</code> &gt; <code>Build &amp; deploy</code> and edit the following commands and then save the changes:</p>
<ul>
<li><p>Build command: <strong>npm run build</strong></p>
</li>
<li><p>Publish directory: <strong>dist</strong></p>
</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--132-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Build and deploy section on Netlify</em></p>
<h3 id="heading-set-the-functions-directory">Set the Functions directory</h3>
<p>By default, Netlify uses <code>netlify/functions</code> as the directory to find the functions to deploy them. In our case, our serverless function <code>getPhotos</code> can be found in the <code>netlify/functions</code> directory.</p>
<p>Now we'll set a custom functions directory so Netlify can find your compiled functions. Go to <code>Site settings</code> &gt; <code>Functions</code> and enter the directory path where the functions are stored in your repository.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--131-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Functions directory section on Netlify</em></p>
<h3 id="heading-how-to-set-environment-variables-for-production">How to Set Environment Variables for Production</h3>
<p>In the Netlify Dashboard, click on <code>Site settings</code> &gt; <code>Build &amp; deploy</code> &gt; <code>Environment</code> &gt; <code>Environment variables</code> and then configure KEY/VALUE pairs as follows:</p>
<pre><code class="lang-plaintext">PIXABAY_API_KEY=your-api-key-here
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--133-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Environment variables section on Netlify</em></p>
<p>Click on Save, and then redeploy your app so the changes can be added.</p>
<p>To redeploy the app on Netlify, navigate to <code>Deploys</code> &gt; <code>Trigger deploy</code>. Next, select <code>Clear cache and redeploy site</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--134-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Trigger redeployment tab on Netlify</em></p>
<p><strong>Note:</strong> The environment variable (PIXABAY_API_KEY) name should match the one mentioned in the <code>getPhotos</code> codebase.</p>
<p>For a React application, prepend the API environment variable with the prefix <code>REACT_APP</code> so they can be read from the <code>.env</code> file.</p>
<pre><code class="lang-plaintext"> REACT_APP_PIXABAY_API_KEY=your-api-key-here
</code></pre>
<h2 id="heading-how-to-initialize-the-serverless-function-to-the-remote-app">How to Initialize the Serverless Function to the Remote App</h2>
<p>To connect your project directory to the existing web app deployed on Netlify, login to your Netlify account from the terminal:</p>
<pre><code class="lang-bash">netlify login
</code></pre>
<p>Next, initialize the app on Netlify by running the command in your terminal:</p>
<pre><code class="lang-bash">netlify init
</code></pre>
<p>Your app is now configured for continuous deployment via Netlify.</p>
<h2 id="heading-how-to-build-the-netlify-serverless-function">How to Build the Netlify Serverless Function</h2>
<p>You need to link your app to site ID on Netlify before running the build command on your terminal. To connect your local project folder to its site ID on Netlify, enter the command in your terminal:</p>
<pre><code class="lang-bash">netlify link
</code></pre>
<p>This will prompt you to link the folder to a site through any of the following options:</p>
<ul>
<li><p>Search by full or partial site name</p>
</li>
<li><p>Choose from a list of your recently updated sites</p>
</li>
<li><p>Enter a site ID</p>
</li>
</ul>
<p>Once you select your preferred option, it will connect the project folder to the hosted site on Netlify. This allows you run <strong>Netlify CLI</strong> commands and also automatically deploy the project repository once there are any changes in the codebase.</p>
<p>In the next step, you will build a serverless function while it is running on the server. To activate the build command defined in <code>netlify.toml</code> file, run the following command:</p>
<pre><code class="lang-bash">netlify build
</code></pre>
<p>This runs the <code>npm run-script</code> command under the hood as specified in the <code>package.json</code>. Now, your serverless function in <code>netlify/functions</code> directory is packaged and bundled successfully!</p>
<h2 id="heading-how-to-test-the-application">How to Test the Application</h2>
<p>To test and confirm that the Netlify function is working fine, run this command on your terminal:</p>
<pre><code class="lang-bash">netlify <span class="hljs-built_in">functions</span>:serve
</code></pre>
<p>This injects your project environment variables from the <strong>.env</strong> file and runs the serverless function.</p>
<h3 id="heading-how-to-confirm-api-keys-security">How to Confirm API Keys Security</h3>
<p>To inspect your app and confirm that the API keys are hidden from the public, follow the steps below:</p>
<p>Click on your hosted app URL, and navigate to <strong>Developer tools</strong> by pressing the <strong>F12</strong> key or right-clicking and selecting <strong>Inspect</strong>. Navigate to <strong>Network</strong> tab, where you should see the fetched data from the Pixabay API.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--128-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>API key hidden from the public and unauthorized parties after inspection through the Developer tools</em></p>
<p>Now you've confirmed that you've successfully configured a serverless function and have it deployed on Netlify.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>This tutorial introduced serverless functions, asynchronous JavaScript, and Restful API concepts.</p>
<p>Hopefully you now know how to create a serverless/lambda function and secure any sensitive value such as API keys in your frontend JavaScript application.</p>
<p>If you got stuck with anything, you can access the complete source code in this <a target="_blank" href="https://github.com/frankiefab100/netlify-serverless-functions-demo/tree/main">GitHub repository</a>.</p>
<p>Thank you for reading! If you have any questions, feel free to reach out to me via <a target="_blank" href="https://twitter.com/frankiefab100">Twitter</a>.</p>
<h2 id="heading-relevant-links"><strong>Relevant Links</strong></h2>
<ul>
<li><p><a target="_blank" href="https://docs.netlify.com/functions/overview/">Netlify Functions</a></p>
</li>
<li><p><a target="_blank" href="https://www.netlify.com/blog/intro-to-serverless-functions/">Netlify Intro to Serverless Functions</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/sdras/netlify-functions-example">Netlify Functions Example</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
