<?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[ Ashutosh K Singh - 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[ Ashutosh K Singh - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 16 May 2026 22:22:24 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/ashutoshksingh/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Job Description Generator with NextJS and ChatGPT ]]>
                </title>
                <description>
                    <![CDATA[ In this tutorial, we will discuss how to build a Job Description Generator with Next.js, and ChatGPT, a powerful language generation model developed by OpenAI. We will also use TailwindCSS, a utility-first CSS framework, to style our Next.js app. Che... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-job-description-generator-with-nextjs-and-chatgpt/</link>
                <guid isPermaLink="false">66ba19a843a303ea8f43c0f7</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tailwind ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh K Singh ]]>
                </dc:creator>
                <pubDate>Wed, 18 Jan 2023 23:50:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/01/m1ieud6fgxhqsgnec96n-1.gif" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this tutorial, we will discuss how to build a Job Description Generator with <a target="_blank" href="https://nextjs.org/">Next.js</a>, and <a target="_blank" href="https://openai.com/blog/chatgpt/">ChatGPT</a>, a powerful language generation model developed by OpenAI.</p>
<p>We will also use <a target="_blank" href="https://tailwindcss.com/">TailwindCSS</a>, a utility-first CSS framework, to style our Next.js app.</p>
<p>Check out the GitHub Repo <a target="_blank" href="https://github.com/lelouchB/ai-job-description">here</a> if you want to jump right into the code.</p>
<p>And here's a link to the deployed version: <a target="_blank" href="https://ai-job-description.vercel.app/">https://ai-job-description.vercel.app/</a>.</p>
<p>Now let's get started.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we get started, you should have:</p>
<ol>
<li>Knowledge of <a target="_blank" href="https://www.freecodecamp.org/learn/responsive-web-design/">HTML, CSS, and JavaScript</a>.</li>
<li>Basic understanding of <a target="_blank" href="https://www.freecodecamp.org/learn/front-end-libraries/react/">React</a> and <a target="_blank" href="https://nextjs.org/">Next.js</a>.</li>
<li><a target="_blank" href="https://nodejs.org/en/">Node</a> and NPM are installed on your local dev machine.</li>
<li>Any code editor of your choice. (example <a target="_blank" href="https://code.visualstudio.com/">VSCode</a>)</li>
</ol>
<p>If you feel like your progress could be improved because you need to learn more about these subjects, check out <a target="_blank" href="https://www.freecodecamp.org/learn">https://www.freecodecamp.org/learn</a>. The awesome modules there will get you started in no time.</p>
<h2 id="heading-how-to-setup-and-install-nextjs"><strong>How to Setup and Install Next.js</strong></h2>
<p>We will use <a target="_blank" href="https://nextjs.org/docs/api-reference/create-next-app">Create Next App</a> to initialize a Next.js project quickly. In your project's root directory, run the following commands in the terminal:</p>
<pre><code class="lang-bash">npx create-next-app@latest ai-job-description --src-dir
<span class="hljs-built_in">cd</span> ai-job-description
npm run dev
</code></pre>
<p>Select <code>No</code> when prompted for extra configs.</p>
<pre><code class="lang-bash">✔ Would you like to use TypeScript with this project? … No / Yes
✔ Would you like to use ESLint with this project? … No / Yes
? Would you like to use experimental `app/` directory with this project? › No / ✔ Would you like to use experimental `app/` directory with this project? … No
</code></pre>
<p>You can run the following command if you want to create a TypeScript project:</p>
<pre><code class="lang-bash">npx create-next-app@latest ai-job-description --typescript --src-dir
<span class="hljs-built_in">cd</span> ai-job-description
npm run dev
</code></pre>
<p>The last command, <code>npm run dev</code>, will start the development server on your system's port 3000.</p>
<p>Navigate to <a target="_blank" href="http://localhost:3000">http://localhost:3000</a> in the browser. Here is what your app will look like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Untitled.png" alt="Next.js 13" width="600" height="400" loading="lazy">
<em>Next.js 13</em></p>
<p>You can now close the development server. The next step is clean the sample code generated by Create Next App and configure the project to use TailwindCSS.</p>
<p>Run the following commands to install TailwindCSS to the project.</p>
<pre><code class="lang-bash">npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
</code></pre>
<p>The last command will create a <code>tailwind.config.js</code> file in your project’s root directory.</p>
<p>Update the <code>tailwind.config.js</code> file like this to include the paths to our files:</p>
<pre><code class="lang-js">
<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">content</span>: [
    <span class="hljs-string">"./src/pages/**/*.{js,ts,jsx,tsx}"</span>,
    <span class="hljs-string">"./src/components/**/*.{js,ts,jsx,tsx}"</span>,
  ],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
};
</code></pre>
<ol>
<li>Delete the <code>src/styles/Home.module.css</code> file.</li>
<li>Update the <code>src/styles/globals.css</code> like this.</li>
</ol>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;
</code></pre>
<ol start="3">
<li>Modify <code>src/pages/index.js</code> like this:</li>
</ol>
<pre><code class="lang-js"><span class="hljs-comment">// src/pages/index.js</span>
<span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;
<span class="hljs-keyword">import</span> { Inter } <span class="hljs-keyword">from</span> <span class="hljs-string">"@next/font/google"</span>;

<span class="hljs-keyword">const</span> inter = Inter({ <span class="hljs-attr">subsets</span>: [<span class="hljs-string">"latin"</span>] });

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>AI Job Description Generator<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"AI Job Description Generator"</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"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</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">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">bg-white</span> <span class="hljs-attr">min-h-screen</span> "}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center justify-center px-4 py-2"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-4xl md:text-6xl font-bold"</span>&gt;</span>
            AI Job Description Generator
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-4xl md:text-6xl font-bold text-blue-600"</span>&gt;</span>
              .
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-3 text-2xl"</span>&gt;</span>
            Create Beautiful
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold text-blue-600"</span>&gt;</span>
              {" "}
              Job Descriptions{" "}
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            in Seconds
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>We added a simple heading and subtitle to our app in the above code. Restart the dev server by running the <code>npm run dev</code> command and again head over to <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> in the browser. Your app will look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Untitled-1-.png" alt="AI Job Description Generator" width="600" height="400" loading="lazy">
<em>AI Job Description Generator</em></p>
<h2 id="heading-how-to-generate-an-openai-api-key">How to Generate an OpenAI API Key</h2>
<p>In this section, we will discuss how you can generate an OpenAI API Key. Head over to <a target="_blank" href="https://beta.openai.com/signup">https://beta.openai.com/signup</a> in the browser and create an account on OpenAI if you still need to do so.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Untitled-2-.png" alt="https://beta.openai.com/signup" width="600" height="400" loading="lazy">
<em>https://beta.openai.com/signup</em></p>
<p>After creating an account, navigate to <a target="_blank" href="https://beta.openai.com/account/api-keys">https://beta.openai.com/account/api-keys</a> and click on <code>+ Create new secret key</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Screenshot-2023-01-18-at-12-06-06-OpenAI-API.png" alt="Create new secret key" width="600" height="400" loading="lazy"></p>
<p>This will generate a new API Key – copy this key. Run the following command to create a <code>.env</code> file:</p>
<pre><code class="lang-bash">touch .env
</code></pre>
<p>Inside this <code>.env</code> file, create a new environment variable named <code>OPENAI_API_KEY</code> and paste the API key there.</p>
<pre><code>OPENAI_API_KEY = <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">REPLACE_WITH_YOUR_KEY</span>&gt;</span></span>
</code></pre><p>Next.js has built-in support for loading environment variables from <code>.env</code> into <code>process.env</code>. You can read more about it <a target="_blank" href="https://nextjs.org/docs/basic-features/environment-variables">here</a>.</p>
<h2 id="heading-how-to-build-the-ui-of-the-app">How to Build the UI of the App</h2>
<p>To generate the Job Descriptions, we need some basic details about the job itself. In this section, we will create the form to take user input. </p>
<p>We will ask the user about Job Title, Industry, Tone, and Keywords to include in the Job Description. You can modify the fields to create a custom Job Description Generator. </p>
<p>For example, if you want to build this for the <strong>Tech</strong> Industry, you can hardcode that info and remove the corresponding fields.</p>
<p>We will show the result of the ChatGPT API request in a text area and give the user the option to copy the output to their clipboard.</p>
<p>Run the following commands in the root directory to create a file named <code>Dashboard.js</code> in the <code>components</code> folder.</p>
<pre><code class="lang-js">cd src
mkdir components
cd components
touch Dashboard.js
</code></pre>
<p>Add the following code to the <code>Dashboard.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [jobDescription, setJobDescription] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> [jobTitle, setJobTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [industry, setIndustry] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [keyWords, setKeyWords] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [tone, setTone] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [numWords, setNumWords] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> [isGenerating, setIsGenerating] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [isCopied, setIsCopied] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 py-12"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid gap-y-12 md:grid-cols-2 md:gap-x-12 "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">""</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">form</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"jobTitle"</span>&gt;</span>
                Job Title
              <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"jobTitle"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Job Title"</span>
                <span class="hljs-attr">id</span>=<span class="hljs-string">"jobTitle"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{jobTitle}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setJobTitle(e.target.value)}
                required
              /&gt;
            <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">"flex flex-col"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"industry"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span>&gt;</span>
                Industry
              <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">value</span>=<span class="hljs-string">{industry}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setIndustry(e.target.value)}
                className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
                placeholder="Industry (Optional)"
                type="text"
                name="industry"
                id="industry"
              /&gt;
            <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">"flex flex-col"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"keywords"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span>&gt;</span>
                Keywords for AI (Optional)
              <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
                <span class="hljs-attr">rows</span>=<span class="hljs-string">{7}</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{keyWords}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setKeyWords(e.target.value)}
                name="keyWords"
                id="keyWords"
                placeholder="Keywords for AI (Optional)"
                className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
              /&gt;
            <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">"flex flex-col"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"tone"</span>&gt;</span>
                Tone
              <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">select</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{tone}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTone(e.target.value)}
                className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
                name="tone"
                id="tone"
              &gt;
                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"default"</span>&gt;</span>Select Tone (Optional)<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"casual"</span>&gt;</span>Casual<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"friendly"</span>&gt;</span>Friendly<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"professional"</span>&gt;</span>Professional<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"formal"</span>&gt;</span>Formal<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">select</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">"flex flex-col"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"words"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span>&gt;</span>
                Words (Optional)
              <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">value</span>=<span class="hljs-string">{numWords}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setNumWords(e.target.value)}
                type="number"
                className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
                placeholder="Number Of Words - Default 200 (Optional)"
                name="words"
                id="words"
              /&gt;
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">bg-blue-600</span> <span class="hljs-attr">w-full</span> <span class="hljs-attr">hover:bg-blue-700</span> <span class="hljs-attr">text-white</span> <span class="hljs-attr">font-bold</span> <span class="hljs-attr">mt-6</span> <span class="hljs-attr">py-2</span> <span class="hljs-attr">px-4</span> <span class="hljs-attr">rounded</span>
                ${
                  <span class="hljs-attr">isGenerating</span> || <span class="hljs-attr">jobTitle</span> === <span class="hljs-string">""</span>
                    ? "<span class="hljs-attr">cursor-not-allowed</span> <span class="hljs-attr">opacity-50</span>"
                    <span class="hljs-attr">:</span> ""
                }`}
              <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
              <span class="hljs-attr">disabled</span>=<span class="hljs-string">{isGenerating</span> || <span class="hljs-attr">jobTitle</span> === <span class="hljs-string">""</span>}
            &gt;</span>
              {isGenerating ? "Generating..." : "Generate Job Description"}
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">""</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"output"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span>&gt;</span>
              Output
            <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
              <span class="hljs-attr">rows</span>=<span class="hljs-string">{</span>
                <span class="hljs-attr">jobDescription</span> === <span class="hljs-string">""</span>
                  ? <span class="hljs-attr">7</span>
                  <span class="hljs-attr">:</span> <span class="hljs-attr">jobDescription.split</span>("\\<span class="hljs-attr">n</span>")<span class="hljs-attr">.length</span> + <span class="hljs-attr">12</span>
              }
              <span class="hljs-attr">name</span>=<span class="hljs-string">"output"</span>
              <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setJobDescription(e.target.value)}
              value={jobDescription}
              disabled={jobDescription === ""}
              id="output"
              placeholder="AI Generated Job Description"
              className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> {}}
              className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
              type="submit"
              disabled={jobDescription === ""}
            &gt;
              {isCopied ? "Copied" : "Copy to Clipboard"}
            <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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Here's what we are doing:</p>
<p>First, we start by importing the <code>useState</code> hook from <code>react</code>. Hooks are functions that allow you to use React features, such as defining state, without having to write a class. </p>
<p>The <code>useState</code> lets you track the state, that is data or properties, in a functional component. Here we are using the <code>useState</code> hook to track the value of all the input fields.</p>
<p>We defined the following states:</p>
<pre><code class="lang-js">  <span class="hljs-keyword">const</span> [jobDescription, setJobDescription] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> [jobTitle, setJobTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [industry, setIndustry] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [keyWords, setKeyWords] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [tone, setTone] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [numWords, setNumWords] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> [isGenerating, setIsGenerating] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [isCopied, setIsCopied] = useState(<span class="hljs-literal">false</span>);
</code></pre>
<p>The <code>jobDescription</code> state is for the job description sent by the ChatGPT API. The <code>jobTitle</code>, <code>industry</code>, <code>keyWords</code>, <code>tone</code> and <code>numWords</code> are the state for all the form fields. The <code>isGenerating</code> is used to track whether the request is being processed after the user hits the <code>Generate</code> button. The <code>isCopied</code> state follows whether the user has copied the output Job Description successfully.</p>
<p>We use <a target="_blank" href="https://tailwindcss.com/docs/grid-template-columns">TailwindCSS</a> to create a grid of two columns. The first column will have the input form, and the other column will render the output Job Description.</p>
<pre><code class="lang-js">&lt;div className=<span class="hljs-string">"grid gap-y-12 md:grid-cols-2 md:gap-x-12"</span>&gt;
...
&lt;/div&gt;
</code></pre>
<p>We create a <code>form</code> element in the first column and define its input fields.</p>
<pre><code class="lang-js">&lt;form&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"jobTitle"</span>&gt;</span>
      Job Title
    <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
      <span class="hljs-attr">className</span>=<span class="hljs-string">"block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"</span>
      <span class="hljs-attr">name</span>=<span class="hljs-string">"jobTitle"</span>
      <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Job Title"</span>
      <span class="hljs-attr">id</span>=<span class="hljs-string">"jobTitle"</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{jobTitle}</span>
      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setJobTitle(e.target.value)}
      required
    /&gt;
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
...
&lt;/form&gt;
</code></pre>
<p>The <code>jobTitle</code> field is the only required field in the form and is needed to generate the Job Description. We set the value of this input field to <code>jobTitle</code> state and pass the <code>setJobTitle()</code> function to the <code>onChange()</code> event which will update the <code>jobTitle</code> whenever the user types inside the input field. Now, the state, <code>jobTitle</code> state and the input field are interlinked.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Untitled-1.png" alt="Job Title Field" width="600" height="400" loading="lazy"></p>
<p>We use the same format to create other input fields for Industry and Number of Words.</p>
<p>For the keywords, we use a <code>textarea</code> for the user to enter any relevant info or keywords for the Job Description.</p>
<pre><code class="lang-js">&lt;div className=<span class="hljs-string">"flex flex-col"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"keywords"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span>&gt;</span>
    Keywords for AI (Optional)
  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
    <span class="hljs-attr">rows</span>=<span class="hljs-string">{7}</span>
    <span class="hljs-attr">value</span>=<span class="hljs-string">{keyWords}</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setKeyWords(e.target.value)}
    name="keyWords"
    id="keyWords"
    placeholder="Keywords for AI (Optional)"
    className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
  /&gt;</span>
&lt;/div&gt;
</code></pre>
<p>Here is how this <code>textarea</code> fields looks:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Untitled-1--1.png" alt="Keywords Field" width="600" height="400" loading="lazy"></p>
<p>We also create a <code>select</code> field for the tone of the Job Description. You can customize the options according to your needs. </p>
<p>This app has four tones – <strong>Casual</strong>, <strong>Friendly</strong>, <strong>Professional</strong>, and <strong>Formal</strong>. Like the input field above for <code>jobTitle</code>, we use the <code>value</code> and <code>onChange</code> event to interlink the <code>select</code> field to the <code>tone</code> state.</p>
<pre><code class="lang-js">&lt;div className=<span class="hljs-string">"flex flex-col"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"tone"</span>&gt;</span>
    Tone
  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span></span>

  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">select</span>
    <span class="hljs-attr">value</span>=<span class="hljs-string">{tone}</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTone(e.target.value)}
    className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
    name="tone"
    id="tone"
  &gt;
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"default"</span>&gt;</span>Select Tone (Optional)<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"casual"</span>&gt;</span>Casual<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"friendly"</span>&gt;</span>Friendly<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"professional"</span>&gt;</span>Professional<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"formal"</span>&gt;</span>Formal<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span></span>
&lt;/div&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Untitled-2--1.png" alt="Tone" width="600" height="400" loading="lazy"></p>
<p>The final field in the form is a <code>button</code> to trigger the generation of the Job Description.</p>
<pre><code class="lang-js">&lt;button
  className={<span class="hljs-string">`bg-blue-600 w-full hover:bg-blue-700 text-white font-bold mt-6 py-2 px-4 rounded
                <span class="hljs-subst">${
                  isGenerating || jobTitle === <span class="hljs-string">""</span>
                    ? <span class="hljs-string">"cursor-not-allowed opacity-50"</span>
                    : <span class="hljs-string">""</span>
                }</span>`</span>}
  type=<span class="hljs-string">"submit"</span>
  disabled={isGenerating || jobTitle === <span class="hljs-string">""</span>}
&gt;
  {isGenerating ? <span class="hljs-string">"Generating..."</span> : <span class="hljs-string">"Generate Job Description"</span>}
&lt;/button&gt;
</code></pre>
<p>We don’t want users to click on the <code>Generate</code> button without any Job Title and create empty requests. So in the above button, we use the <code>isGenerating</code> and <code>jobTitle</code> state to disable the button when the <code>jobTitle</code> is empty. We also change the button's text to <code>Generating</code> when the API request is in process.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Untitled-3-.png" alt="Generate Job Description button" width="600" height="400" loading="lazy"></p>
<p>We add a <code>textarea</code> field to display the output Job Description in the second column. This <code>textarea</code> is disabled while the <code>jobDescription</code> state is empty.</p>
<pre><code class="lang-js">&lt;div className=<span class="hljs-string">"flex flex-col"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"output"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span>&gt;</span>
    Output
  <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
    <span class="hljs-attr">rows</span>=<span class="hljs-string">{jobDescription</span> === <span class="hljs-string">""</span> ? <span class="hljs-attr">7</span> <span class="hljs-attr">:</span> <span class="hljs-attr">jobDescription.split</span>("\\<span class="hljs-attr">n</span>")<span class="hljs-attr">.length</span> + <span class="hljs-attr">12</span>}
    <span class="hljs-attr">name</span>=<span class="hljs-string">"output"</span>
    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setJobDescription(e.target.value)}
    value={jobDescription}
    disabled={jobDescription === ""}
    id="output"
    placeholder="AI Generated Job Description"
    className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
  /&gt;</span>
  ...
&lt;/div&gt;
</code></pre>
<p>We also add a copy button to the second column so users can easily copy the output Job Description. This button is also disabled while the <code>jobDescription</code> state is empty.</p>
<pre><code class="lang-js">&lt;button
  onClick={<span class="hljs-function">() =&gt;</span> {}}
  className=<span class="hljs-string">"bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"</span>
  type=<span class="hljs-string">"submit"</span>
  disabled={jobDescription === <span class="hljs-string">""</span>}
&gt;
  {isCopied ? <span class="hljs-string">"Copied"</span> : <span class="hljs-string">"Copy to Clipboard"</span>}
&lt;/button&gt;
</code></pre>
<p>Here is how the second column looks:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Untitled-4-.png" alt="Output Column" width="600" height="400" loading="lazy"></p>
<p>Next, we update the <code>index.js</code> file like this to import and add the <code>Dashboard</code> component:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;
<span class="hljs-keyword">import</span> { Inter } <span class="hljs-keyword">from</span> <span class="hljs-string">"@next/font/google"</span>;
<span class="hljs-keyword">import</span> Dashboard <span class="hljs-keyword">from</span> <span class="hljs-string">"@/components/Dashboard"</span>;

<span class="hljs-keyword">const</span> inter = Inter({ <span class="hljs-attr">subsets</span>: [<span class="hljs-string">"latin"</span>] });

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>AI Job Description Generator<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"AI Job Description Generator"</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"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</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">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>"<span class="hljs-attr">bg-white</span> <span class="hljs-attr">min-h-screen</span> "}&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center justify-center px-4 py-2"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-4xl md:text-6xl font-bold"</span>&gt;</span>
            AI Job Description Generator
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-4xl md:text-6xl font-bold text-blue-600"</span>&gt;</span>
              .
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-3 text-2xl"</span>&gt;</span>
            Create Beautiful
            <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold text-blue-600"</span>&gt;</span>
              {" "}
              Job Descriptions{" "}
            <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            in Seconds
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Dashboard</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span>
    <span class="hljs-tag">&lt;/&gt;</span></span>
  );
}
</code></pre>
<p>Your app will look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/Untitled-5-.png" alt="AI Job Description Generator" width="600" height="400" loading="lazy"></p>
<p>You can add values to the empty fields, but it's not functional yet. We will add the logic to fetch and display the Job Description in the next section.</p>
<h2 id="heading-how-to-fetch-data-from-chatgpt">How to Fetch Data from ChatGPT</h2>
<p>In this section, we will discuss how you can create a Next.js API route that sends a request to ChatGPT to generate the Job Description from user input data.</p>
<p>Next.js provides an easy solution to build your API without needing another project, for example, a Node-Express project.</p>
<p>From the <a target="_blank" href="https://nextjs.org/docs/api-routes/introduction">NextJS Docs</a>:</p>
<blockquote>
<p><em>Files in the folder pages/api are mapped to the /api/ route and treated as API endpoints rather than pages. These files are server-side only and do not add to the size of the client-side bundle.*</em></p>
</blockquote>
<p>First, run the following command in the project's root to create an API route.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> src/pages/api
touch returnJobDescription.js
</code></pre>
<p>Then add the following code to the <code>returnJobDescription.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> generateDescription = <span class="hljs-keyword">async</span> ({
  jobTitle,
  industry,
  keyWords,
  tone,
  numWords,
}) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
      <span class="hljs-string">"https://api.openai.com/v1/engines/text-davinci-003/completions"</span>,
      {
        <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
        <span class="hljs-attr">headers</span>: {
          <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
          <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${process.env.OPENAI_API_KEY}</span>`</span>,
        },
        <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
          <span class="hljs-attr">prompt</span>: <span class="hljs-string">`Write a job description for a  <span class="hljs-subst">${jobTitle}</span> role 
          <span class="hljs-subst">${industry ? <span class="hljs-string">`in the <span class="hljs-subst">${industry}</span> industry`</span> : <span class="hljs-string">""</span>}</span> that is around <span class="hljs-subst">${
            numWords || <span class="hljs-number">200</span>
          }</span> words in a <span class="hljs-subst">${tone || <span class="hljs-string">"neutral"</span>}</span> tone. <span class="hljs-subst">${
            keyWords ? <span class="hljs-string">`Incorporate the following keywords: <span class="hljs-subst">${keyWords}</span>.`</span> : <span class="hljs-string">""</span>
          }</span>. The job position should be described in a way that is SEO friendly, highlighting its unique features and benefits.`</span>,
          <span class="hljs-attr">max_tokens</span>: <span class="hljs-number">100</span>,
          <span class="hljs-attr">temperature</span>: <span class="hljs-number">0.5</span>,
        }),
      }
    );
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();

    <span class="hljs-keyword">return</span> data.choices[<span class="hljs-number">0</span>].text;
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err);
  }
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">const</span> { jobTitle, industry, keyWords, tone, numWords } = req.body;

  <span class="hljs-keyword">const</span> jobDescription = <span class="hljs-keyword">await</span> generateDescription({
    jobTitle,
    industry,
    keyWords,
    tone,
    numWords,
  });

  res.status(<span class="hljs-number">200</span>).json({
    jobDescription,
  });
}
</code></pre>
<p>Here’s what we are doing:</p>
<p>First, we create an async function named <code>generateJobDescription</code> that takes <code>jobTitle</code>, <code>industry</code>, <code>tone</code>, <code>numWords</code> and <code>keywords</code> as arguments.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> generateDescription = <span class="hljs-keyword">async</span> ({
  jobTitle,
  industry,
  keyWords,
  tone,
  numWords,
}) =&gt; {
...
}
</code></pre>
<p>Then we then use <code>fetch</code> API inside a try/catch block to create a <code>POST</code> request to the OpenAI ChatGPT endpoint. You can read more about <code>fetch</code> API <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">here</a>. You can also use the <a target="_blank" href="https://www.npmjs.com/package/openai">OpenAI NodeJS package</a> instead of the <code>fetch</code> API.</p>
<p>The requests are sent to the following endpoint: <code>https://api.openai.com/v1/engines/text-davinci-003/completions</code></p>
<p>Here the <code>text-davinci-003</code> is the model for the ChatGPT, and <code>completions</code> is the task we want to perform. You can read about other OpenAI models <a target="_blank" href="https://beta.openai.com/docs/models/gpt-3">here</a>.</p>
<pre><code class="lang-js">  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(
      <span class="hljs-string">"https://api.openai.com/v1/engines/text-davinci-003/completions"</span>,
      {
        <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
        <span class="hljs-attr">headers</span>: {
          <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
          <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${process.env.OPENAI_API_KEY}</span>`</span>,
        },
        <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
          <span class="hljs-attr">prompt</span>: <span class="hljs-string">`Write a job description for a  <span class="hljs-subst">${jobTitle}</span> role 
          <span class="hljs-subst">${industry ? <span class="hljs-string">`in the <span class="hljs-subst">${industry}</span> industry`</span> : <span class="hljs-string">""</span>}</span> that is around <span class="hljs-subst">${
            numWords || <span class="hljs-number">200</span>
          }</span> words in a <span class="hljs-subst">${tone || <span class="hljs-string">"neutral"</span>}</span> tone. <span class="hljs-subst">${
            keyWords ? <span class="hljs-string">`Incorporate the following keywords: <span class="hljs-subst">${keyWords}</span>.`</span> : <span class="hljs-string">""</span>
          }</span>. The job position should be described in a way that is SEO friendly, highlighting its unique features and benefits.`</span>,
          <span class="hljs-attr">max_tokens</span>: <span class="hljs-number">100</span>,
          <span class="hljs-attr">temperature</span>: <span class="hljs-number">0.5</span>,
        }),
      }
    );

...
}
<span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err);
  }
</code></pre>
<p>The OpenAI API uses the API key we generated previously to authenticate the requests. We add it to the <code>Authorization</code> HTTP header like this:</p>
<pre><code class="lang-js">headers: {
 <span class="hljs-attr">Authorization</span>: <span class="hljs-string">`Bearer <span class="hljs-subst">${process.env.OPENAI_API_KEY}</span>`</span>,
},
</code></pre>
<p>In the <code>body</code> of the <code>POST</code> request, we add the user input values to a pre-configured prompt for the Job Description. This prompt can be a string, array of strings, array of tokens, or array of token arrays. You can customize this prompt accordingly. </p>
<p>We have added a default value for <code>numWords</code> and <code>tone</code> in the prompt, that is <code>200</code> and <code>neutral</code>, respectively. You can read more about this <a target="_blank" href="https://beta.openai.com/docs/api-reference/completions/create">here</a>.</p>
<pre><code class="lang-js">body: <span class="hljs-built_in">JSON</span>.stringify({
    <span class="hljs-attr">prompt</span>: <span class="hljs-string">`Write a job description for a  <span class="hljs-subst">${jobTitle}</span> role 
          <span class="hljs-subst">${industry ? <span class="hljs-string">`in the <span class="hljs-subst">${industry}</span> industry`</span> : <span class="hljs-string">""</span>}</span> that is around <span class="hljs-subst">${
        numWords || <span class="hljs-number">200</span>
    }</span> words in a <span class="hljs-subst">${tone || <span class="hljs-string">"neutral"</span>}</span> tone. <span class="hljs-subst">${
        keyWords ? <span class="hljs-string">`Incorporate the following keywords: <span class="hljs-subst">${keyWords}</span>.`</span> : <span class="hljs-string">""</span>
    }</span>. The job position should be described in a way that is SEO friendly, highlighting its unique features and benefits.`</span>,
    <span class="hljs-attr">max_tokens</span>: <span class="hljs-number">100</span>,
    <span class="hljs-attr">temperature</span>: <span class="hljs-number">0.5</span>,
})
</code></pre>
<p>Tokens are common sequences of characters found in the text. The <code>max_tokens</code> is the maximum token used to generate the Job Description. You can read more about tokens <a target="_blank" href="https://beta.openai.com/tokenizer">here</a>.</p>
<p>The <code>temperature</code> specifies the <a target="_blank" href="https://towardsdatascience.com/how-to-sample-from-language-models-682bceb97277">sampling temperature</a> to use. Higher values means the model will take more risks. For example, 0.9 will be best for more creative applications, and 0 (argmax sampling) for the ones with a well-defined answer.</p>
<p>Finally, we parse the response stream from OpenAI API to JSON format and return it from the function. You can read more about the <code>json()</code> method <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Response/json">here</a>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
<span class="hljs-keyword">return</span> data.choices[<span class="hljs-number">0</span>].text;
</code></pre>
<p>This <code>generateDescription</code> function is used inside the NextJS API route handler, and the output from OpenAI API is returned from the API route.</p>
<pre><code class="lang-js"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">handler</span>(<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">const</span> { jobTitle, industry, keyWords, tone, numWords } = req.body;

  <span class="hljs-keyword">const</span> jobDescription = <span class="hljs-keyword">await</span> generateDescription({
    jobTitle,
    industry,
    keyWords,
    tone,
    numWords,
  });

  res.status(<span class="hljs-number">200</span>).json({
    jobDescription,
  });
}
</code></pre>
<h2 id="heading-how-to-integrate-the-nextjs-api-route">How to Integrate the NextJS API Route</h2>
<p>We have created the UI and the API route. Now its time to bring them together and complete our app. In this section, we will integrate our frontend and backend together.</p>
<p>First, create a function named <code>handleSubmit</code> in <code>Dashboard.js</code> file right below where you defined the states.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    setIsGenerating(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"/api/returnJobDescription"</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        jobTitle,
        industry,
        keyWords,
        tone,
        numWords,
      }),
    });
    setIsGenerating(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();
    setJobDescription(data.jobDescription.trim());
  };
</code></pre>
<p>In the above function, we first prevent the page from reloading using <code>e.preventDefault()</code> when the <code>form</code> is submitted. We then update the <code>isGenerating</code> state to <code>true</code> using <code>setIsGenerating(true)</code>.</p>
<p>We again use the <code>fetch</code> API to send a POST request to our NextJS API route <code>/api/returnJobDescription</code> with the user input values in the request's <code>body</code>.</p>
<pre><code class="lang-js">body: <span class="hljs-built_in">JSON</span>.stringify({
    jobTitle,
    industry,
    keyWords,
    tone,
    numWords,
})
</code></pre>
<p>After the request, we set the <code>isGenerating</code> state back to <code>false</code>. Then we convert the response to JSON format and set it to the <code>jobDescription</code> state.</p>
<pre><code class="lang-js">setIsGenerating(<span class="hljs-literal">false</span>);
<span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();
setJobDescription(data.jobDescription.trim());
</code></pre>
<p>Next, update the <code>form</code> with the <code>onSubmit</code> event and pass the <code>handleSubmit()</code> function to it</p>
<pre><code class="lang-js">&lt;form onSubmit={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> handleSubmit(e)}&gt;
...
&lt;/form&gt;
</code></pre>
<p>Finally, we create the <code>handleCopy</code> function to copy the <code>jobDescription</code> state to the clipboard.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> handleCopy = <span class="hljs-function">() =&gt;</span> {
    navigator.clipboard.writeText(jobDescription);
    setIsCopied(<span class="hljs-literal">true</span>);
  };
</code></pre>
<p>Update the <code>Copy to Clipboard</code> like this:</p>
<pre><code class="lang-js">&lt;button
    onClick={handleCopy}
    className=<span class="hljs-string">"bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"</span>
    type=<span class="hljs-string">"submit"</span>
    disabled={jobDescription === <span class="hljs-string">""</span>}
&gt;
    {isCopied ? <span class="hljs-string">"Copied"</span> : <span class="hljs-string">"Copy to Clipboard"</span>}
&lt;/button&gt;
</code></pre>
<p>Here is the complete code for the <code>Dashboard.js</code> file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Dashboard</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [jobDescription, setJobDescription] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> [jobTitle, setJobTitle] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [industry, setIndustry] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [keyWords, setKeyWords] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [tone, setTone] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [numWords, setNumWords] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> [isGenerating, setIsGenerating] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> [isCopied, setIsCopied] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">const</span> handleCopy = <span class="hljs-function">() =&gt;</span> {
    navigator.clipboard.writeText(jobDescription);
    setIsCopied(<span class="hljs-literal">true</span>);
  };

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    e.preventDefault();
    setIsGenerating(<span class="hljs-literal">true</span>);
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"/api/returnJobDescription"</span>, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
      },
      <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({
        jobTitle,
        industry,
        keyWords,
        tone,
        numWords,
      }),
    });
    setIsGenerating(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();
    setJobDescription(data.jobDescription.trim());
  };

  <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">"max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 py-12"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid gap-y-12 md:grid-cols-2 md:gap-x-12 "</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">""</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{(e)</span> =&gt;</span> handleSubmit(e)}&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"jobTitle"</span>&gt;</span>
                Job Title
              <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"</span>
                <span class="hljs-attr">name</span>=<span class="hljs-string">"jobTitle"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Job Title"</span>
                <span class="hljs-attr">id</span>=<span class="hljs-string">"jobTitle"</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{jobTitle}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setJobTitle(e.target.value)}
                required
              /&gt;
            <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">"flex flex-col"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"industry"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span>&gt;</span>
                Industry
              <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">value</span>=<span class="hljs-string">{industry}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setIndustry(e.target.value)}
                className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
                placeholder="Industry (Optional)"
                type="text"
                name="industry"
                id="industry"
              /&gt;
            <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">"flex flex-col"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"keywords"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span>&gt;</span>
                Keywords for AI (Optional)
              <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
                <span class="hljs-attr">rows</span>=<span class="hljs-string">{7}</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{keyWords}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setKeyWords(e.target.value)}
                name="keyWords"
                id="keyWords"
                placeholder="Keywords for AI (Optional)"
                className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
              /&gt;
            <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">"flex flex-col"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"tone"</span>&gt;</span>
                Tone
              <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">select</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{tone}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTone(e.target.value)}
                className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
                name="tone"
                id="tone"
              &gt;
                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"default"</span>&gt;</span>Select Tone (Optional)<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"casual"</span>&gt;</span>Casual<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"friendly"</span>&gt;</span>Friendly<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"professional"</span>&gt;</span>Professional<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"formal"</span>&gt;</span>Formal<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">select</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">"flex flex-col"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"words"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span>&gt;</span>
                Words (Optional)
              <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">value</span>=<span class="hljs-string">{numWords}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setNumWords(e.target.value)}
                type="number"
                className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
                placeholder="Number Of Words - Default 200 (Optional)"
                name="words"
                id="words"
              /&gt;
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">bg-blue-600</span> <span class="hljs-attr">w-full</span> <span class="hljs-attr">hover:bg-blue-700</span> <span class="hljs-attr">text-white</span> <span class="hljs-attr">font-bold</span> <span class="hljs-attr">mt-6</span> <span class="hljs-attr">py-2</span> <span class="hljs-attr">px-4</span> <span class="hljs-attr">rounded</span>
                ${
                  <span class="hljs-attr">isGenerating</span> || <span class="hljs-attr">jobTitle</span> === <span class="hljs-string">""</span>
                    ? "<span class="hljs-attr">cursor-not-allowed</span> <span class="hljs-attr">opacity-50</span>"
                    <span class="hljs-attr">:</span> ""
                }`}
              <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
              <span class="hljs-attr">disabled</span>=<span class="hljs-string">{isGenerating</span> || <span class="hljs-attr">jobTitle</span> === <span class="hljs-string">""</span>}
            &gt;</span>
              {isGenerating ? "Generating..." : "Generate Job Description"}
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">""</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"output"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"sr-only"</span>&gt;</span>
              Output
            <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
              <span class="hljs-attr">rows</span>=<span class="hljs-string">{</span>
                <span class="hljs-attr">jobDescription</span> === <span class="hljs-string">""</span>
                  ? <span class="hljs-attr">7</span>
                  <span class="hljs-attr">:</span> <span class="hljs-attr">jobDescription.split</span>("\<span class="hljs-attr">n</span>")<span class="hljs-attr">.length</span> + <span class="hljs-attr">12</span>
              }
              <span class="hljs-attr">name</span>=<span class="hljs-string">"output"</span>
              <span class="hljs-attr">value</span>=<span class="hljs-string">{jobDescription}</span>
              <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setJobDescription(e.target.value)}
              disabled={jobDescription === ""}
              id="output"
              placeholder="AI Generated Job Description"
              className="block w-full rounded-md bg-white border border-gray-400 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm px-4 py-2 placeholder-gray-500 my-2 text-gray-900"
            /&gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{handleCopy}</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
              <span class="hljs-attr">disabled</span>=<span class="hljs-string">{jobDescription</span> === <span class="hljs-string">""</span>}
            &gt;</span>
              {isCopied ? "Copied" : "Copy to Clipboard"}
            <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 class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Here is the above code in action:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/01/m1ieud6fgxhqsgnec96n-2.gif" alt="m1ieud6fgxhqsgnec96n.gif" width="600" height="400" loading="lazy"></p>
<h2 id="heading-you-did-it">You did it! 🎉</h2>
<p>Congrats 👏 on building this <strong>AI Job Description Generator</strong> project.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we learned how to build a Job Description Generator with Next.js using the OpenAI ChatGPT.</p>
<p>We also discussed how to install TailwindCSS to a NextJS project and how to create Next.js API routes.</p>
<p>Here are some additional resources that can be helpful:</p>
<ul>
<li><a target="_blank" href="https://nextjs.org/docs/getting-started">Next.js Docs</a></li>
<li><a target="_blank" href="https://beta.openai.com/docs/introduction/overview">OpenAI Docs</a></li>
<li><a target="_blank" href="https://tailwindcss.com/docs/installation">TailwindCSS Docs</a></li>
</ul>
<p><em>This tutorial is a preview from one of the projects of the free ebook 8 AI Projects. You can get early access to the full 8 project tutorials <a target="_blank" href="http://8aiprojects.com/">8AIProjects</a>.</em></p>
<p>If you're inspired to add features yourself, please do share and <a target="_blank" href="https://twitter.com/noharashutosh">tag me</a> – I'd love to hear about them :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 10 Awesome JavaScript Libraries You Should Try Out ]]>
                </title>
                <description>
                    <![CDATA[ JavaScript is one of the most popular languages on the web. Even though it was initially developed just for web pages, it has seen exponential growth in the past two decades. Now, JavaScript is capable of doing almost anything and works on several pl... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/10-javascript-libraries-you-should-try/</link>
                <guid isPermaLink="false">66ba19a54a85bb09c10a6990</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Libraries ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh K Singh ]]>
                </dc:creator>
                <pubDate>Sun, 03 Jan 2021 17:32:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9999740569d1a4ca20a6.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>JavaScript is one of the most popular languages on the web. Even though it was initially developed just for web pages, it has seen exponential growth in the past two decades.</p>
<p>Now, JavaScript is capable of doing almost anything and works on several platforms and devices including IoT. And with the recent SpaceX Dragon launch, JavaScript is even in space.</p>
<p>One of the reasons for its popularity is the availability of a large number of frameworks and libraries. They make development much easier compared to traditional Vanilla JS development.</p>
<p>There are libraries for almost anything and more are coming out almost every day. But with so many libraries to choose from it becomes difficult to keep a track of each one and how it might be tailored specifically to your needs.</p>
<p>In this article, we will discuss 10 of the most popular JS libraries which you can use to build your next project.</p>
<h1 id="heading-leaflethttpsleafletjscom"><a target="_blank" href="https://leafletjs.com/">Leaflet</a></h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-17.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Leaflet</em></p>
<p>I think Leaflet is the best open source library for adding mobile-friendly interactive maps to your application.</p>
<p>Its small size (39kB) makes it a great alternative to consider over other map libraries. With cross-platform efficiency and a well-documented API, it has everything you need to make you fall in love.</p>
<p>Here is some sample code that creates a Leaflet map:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> map = <span class="hljs-keyword">new</span> L.Map(<span class="hljs-string">"map"</span>, {
    <span class="hljs-attr">center</span>: <span class="hljs-keyword">new</span> L.LatLng(<span class="hljs-number">40.7401</span>, <span class="hljs-number">-73.9891</span>),
    <span class="hljs-attr">zoom</span>: <span class="hljs-number">12</span>,
    <span class="hljs-attr">layers</span>: <span class="hljs-keyword">new</span> L.TileLayer(<span class="hljs-string">"https://tile.openstreetmap.org/{z}/{x}/{y}.png"</span>)
});
</code></pre>
<p>In Leaflet, we need to provide a tile layer since there isn't one by default. But that also means that can choose from a wide range of layers both free and premium. You can explore various free tile layers <a target="_blank" href="https://leaflet-extras.github.io/leaflet-providers/preview/">here</a>.</p>
<p>Read the <a target="_blank" href="https://leafletjs.com/reference-1.6.0.html">Docs</a> or follow the <a target="_blank" href="https://leafletjs.com/examples.html">Tutorials</a> to learn more.</p>
<h1 id="heading-fullpagejshttpsalvarotrigocomfullpage"><a target="_blank" href="https://alvarotrigo.com/fullPage/">fullPage.js</a></h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/ezgif.com-video-to-gif-1--1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This open-source library helps you create full-screen scrolling websites as you can see in the above GIF. It's easy to use and has many options to customize, so it's no surprise it is used by thousands of developers and has over 30k stars on GitHub.</p>
<p>Here is a Codepen demo that you can play with:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/lelouchb/embed/WNrLvLG" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>You can even use it with popular frameworks such as:</p>
<ul>
<li><p><a target="_blank" href="https://alvarotrigo.com/react-fullpage/">react-fullpage</a></p>
</li>
<li><p><a target="_blank" href="https://alvarotrigo.com/vue-fullpage/">vue-fullpage</a></p>
</li>
<li><p><a target="_blank" href="https://alvarotrigo.com/angular-fullpage/">angular-fullpage</a></p>
</li>
</ul>
<p>I came across this library about a year ago and since then it has become one of my favorites. This is one of the few libraries that you can use in almost every project. If you haven't already started using it then just try it, you will not be disappointed.</p>
<h1 id="heading-animejshttpsanimejscom"><a target="_blank" href="https://animejs.com/">anime.js</a></h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/anime.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>anime.js</em></p>
<p>One of the best animation libraries out there, Anime.js is flexible and simple to use. It is the perfect tool to help you add some really cool animation to your project.</p>
<p>Anime.js works well with CSS properties, SVG, DOM attributes, and JavaScript Objects and can be easily integrated into your applications.</p>
<p>As a developer it's important to have a good portfolio. The first impression people have of your portfolio helps decide whether they will hire you or not. And what better tool than this library to bring life to your portfolio. It will not only enhance your website but will help showcase actual skills.</p>
<p>Check out this Codepen to learn more:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/lelouchb/embed/XWXoboE" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>You can also take a look at all the other cool projects on <a target="_blank" href="https://codepen.io/collection/XLebem">Codepen</a> or <a target="_blank" href="https://animejs.com/documentation/">Read the Docs here</a>.</p>
<h1 id="heading-screenfulljshttpsgithubcomsindresorhusscreenfulljs"><a target="_blank" href="https://github.com/sindresorhus/screenfull.js">Screenfull.js</a></h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-29.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>screenfull.js</em></p>
<p>I came across this library while searching for a way to implement a full-screen feature in my project.</p>
<p>If you also want to have a full-screen feature, I would recommend using this library instead of <a target="_blank" href="https://developer.mozilla.org/en/DOM/Using_full-screen_mode">Fullscreen API</a> because of its cross-browser efficiency (although it is built on top of that).</p>
<p>It is so small that you won't even notice it – just about 0.7kB gzipped.</p>
<p>Try the <a target="_blank" href="https://sindresorhus.com/screenfull.js">Demo</a> or read the <a target="_blank" href="https://github.com/sindresorhus/screenfull.js">Docs</a> to learn more.</p>
<h1 id="heading-momentjshttpsmomentjscom"><a target="_blank" href="https://momentjs.com/">Moment.js</a></h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-18.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Moment.js</em></p>
<p>Working with date and time can be a huge pain, especially with API calls, different Time Zones, local languages, and so on. Moment.js can help you solve all those issues whether it is manipulating, validating, parsing, or formatting dates or time.</p>
<p>There are so many cool methods that are really useful for your projects. For example, I used the <code>.fromNow()</code> method in one of my blog projects to show the time the article was published.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> moment = <span class="hljs-built_in">require</span>(<span class="hljs-string">'moment'</span>); 

relativeTimeOfPost = moment([<span class="hljs-number">2019</span>, <span class="hljs-number">07</span>, <span class="hljs-number">13</span>]).fromNow(); 
<span class="hljs-comment">// a year ago</span>
</code></pre>
<p>Although I don't use it very often, I am a fan of its support for internationalization. For example, we can customize the above result using the <code>.locale()</code> method.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// French</span>
moment.locale(<span class="hljs-string">'fr'</span>);
relativeTimeOfPostInFrench = moment([<span class="hljs-number">2019</span>, <span class="hljs-number">07</span>, <span class="hljs-number">13</span>]).fromNow(); 
<span class="hljs-comment">//il y a un an</span>

<span class="hljs-comment">// Spanish</span>
moment.locale(<span class="hljs-string">'es'</span>);
relativeTimeOfPostInSpanish = moment([<span class="hljs-number">2019</span>, <span class="hljs-number">07</span>, <span class="hljs-number">13</span>]).fromNow(); 
<span class="hljs-comment">//hace un año</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/ezgif.com-video-to-gif.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Moment.js Homepage</em></p>
<p>Read the <a target="_blank" href="https://momentjs.com/">Docs here</a>.</p>
<p><strong>Update September 2020:</strong> Moment.js has entered maintenance mode. Read more about it <a target="_blank" href="https://momentjs.com/docs/#/-project-status/">here</a>. You may want to explore alternatives such as <a target="_blank" href="https://day.js.org/">Day.js</a> or <a target="_blank" href="https://date-fns.org/">date-fns</a>.</p>
<h1 id="heading-hammerjshttphammerjsgithubio"><a target="_blank" href="http://hammerjs.github.io/">Hammer.js</a></h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/ezgif.com-video-to-gif-2.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Hammer.js is a lightweight JavaScript library that lets you add multi-touch gestures to your Web Apps.</p>
<p>I would recommend this library to add some fun to your components. Here is an example to play with. Just run the pen and tap or click on the grey div.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/lelouchb/embed/abdPOPj" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>It can recognize gestures made by touch, mouse and pointerEvents. For jQuery users I would recommend using the <a target="_blank" href="http://hammerjs.github.io/jquery-plugin/">jQuery plugin</a>.</p>
<pre><code class="lang-javascript">$(element).hammer(options).bind(<span class="hljs-string">"pan"</span>, myPanHandler);
</code></pre>
<p>Read the <a target="_blank" href="http://hammerjs.github.io/getting-started/">Docs here</a>.</p>
<h1 id="heading-masonryhttpsmasonrydesandrocom"><a target="_blank" href="https://masonry.desandro.com/">Masonry</a></h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-20.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Masonry</em></p>
<p>Masonry is a JavaScript grid layout library. It is super awesome and I use it for many of my projects. It can take your simple grid elements and place them based on the available vertical space, sort of like how contractors fit stones or blocks into a wall.</p>
<p>You can use this library to show your projects in a different light. Use it with cards, images, modals, and so on.</p>
<p>Here is a simple example to show you the magic in action. Well, not magic exactly, but how the layout changes when you <strong>zoom in</strong> on the web page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/ezgif.com-crop.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And here is the code for the above:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">var</span> elem = <span class="hljs-built_in">document</span>.querySelector(<span class="hljs-string">'.grid'</span>);
<span class="hljs-keyword">var</span> msnry = <span class="hljs-keyword">new</span> Masonry( elem, {
  <span class="hljs-attr">itemSelector</span>: <span class="hljs-string">'.grid-item'</span>,
  <span class="hljs-attr">columnWidth</span>: <span class="hljs-number">400</span>
});

<span class="hljs-keyword">var</span> msnry = <span class="hljs-keyword">new</span> Masonry( <span class="hljs-string">'.grid'</span>);
</code></pre>
<p>Here is a cool demo on Codepen:</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/lelouchb/embed/qBbLdLQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<p> </p>
<p>Check out these Projects</p>
<ul>
<li><p><a target="_blank" href="https://halcyon-theme.tumblr.com/">https://halcyon-theme.tumblr.com/</a></p>
</li>
<li><p><a target="_blank" href="https://tympanus.net/Development/GridLoadingEffects/index.html">https://tympanus.net/Development/GridLoadingEffects/index.html</a></p>
</li>
<li><p><a target="_blank" href="https://www.erikjo.com/work">https://www.erikjo.com/work</a></p>
</li>
</ul>
<h1 id="heading-d3jshttpsd3jsorg"><a target="_blank" href="https://d3js.org/">D3.js</a></h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-30.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you are a data-obsessed developer then this library is for you. I have yet to find a library that manipulates data as efficiently and beautifully as D3. With over 92k stars on GitHub, D3 is the favorite data visualization library of many developers.</p>
<p>I recently used D3 to visualize COVID-19 data with React and the <a target="_blank" href="https://github.com/CSSEGISandData/COVID-19">Johns Hopkins CSSE Data Repository on GitHub</a>. It I was a really interesting project, and if you are thinking of doing something similar, I would suggest giving D3.js a try.</p>
<p>Read more about it <a target="_blank" href="https://github.com/d3/d3/wiki">here</a>.</p>
<h1 id="heading-slickhttpskenwheelergithubioslick"><a target="_blank" href="https://kenwheeler.github.io/slick/">slick</a></h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-23.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>slick</em></p>
<p>Slick is fully responsive, swipe-enabled, infinite looping, and more. As mentioned on the homepage it truly is the last carousel you'll ever need.</p>
<p>I have been using this library for quite a while, and it has saved me so much time. With just a few lines of code, you can add so many features to your carousel.</p>
<pre><code class="lang-js">$(<span class="hljs-string">'.autoplay'</span>).slick({
  <span class="hljs-attr">slidesToShow</span>: <span class="hljs-number">3</span>,
  <span class="hljs-attr">slidesToScroll</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">autoplay</span>: <span class="hljs-literal">true</span>,
  <span class="hljs-attr">autoplaySpeed</span>: <span class="hljs-number">2000</span>,
});
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/ezgif.com-video-to-gif-2-.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Autoplay</em></p>
<p>Check out the demos <a target="_blank" href="https://kenwheeler.github.io/slick/">here</a>.</p>
<h1 id="heading-popperjshttpspopperjsorg"><a target="_blank" href="https://popper.js.org/">Popper.js</a></h1>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-25.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Popper.js</em></p>
<p>Popper.js is a lightweight ~3 kB JavaScript library with zero dependencies that provides a reliable and extensible positioning engine you can use to ensure all your popper elements are positioned in the right place.</p>
<p>It may not seem important to spend time configuring popper elements, but these little things are what make you stand out as a developer. And with such small size it doesn't take up much space.</p>
<p>Read the <a target="_blank" href="https://popper.js.org/docs/v2/">Docs here</a>.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>As a developer, having and using the right JavaScript libraries is important. It will make you more productive and will make development much easier and faster. In the end, it is up to you which library to prefer based on your needs.</p>
<p>These are 10 JavaScript libraries that you can try and start using in your projects today. What other cool JavaScript libraries you use? Would you like another article like this? <a target="_blank" href="https://twitter.com/noharashutosh">Tweet</a> and let me know.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an Image Gallery with NextJS using the Pexels API and Chakra UI ]]>
                </title>
                <description>
                    <![CDATA[ In this article, we will build an Image Gallery with Next.js using the Pexels API and Chakra UI v1, a modular and accessible component library.  We will also use the Next.js Image component to optimize the images fetched from the Pexels API. If you w... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-an-image-gallery-with-nextjs/</link>
                <guid isPermaLink="false">66ba19ac1b08c4f4645ed9eb</guid>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh K Singh ]]>
                </dc:creator>
                <pubDate>Mon, 16 Nov 2020 14:55:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/Screenshot_2020-11-12-NextJS-Image-Gallery-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, we will build an Image Gallery with <a target="_blank" href="https://nextjs.org/">Next.js</a> using the <a target="_blank" href="https://www.pexels.com/api/">Pexels API</a> and <a target="_blank" href="https://chakra-ui.com/">Chakra UI v1</a>, a modular and accessible component library. </p>
<p>We will also use the <a target="_blank" href="https://nextjs.org/blog/next-10#built-in-image-component-and-automatic-image-optimization">Next.js Image component</a> to optimize the images fetched from the Pexels API.</p>
<p>If you want to jump right into the code, check out the <a target="_blank" href="https://github.com/lelouchB/next-image-gallery">GitHub Repo here</a>.</p>
<p>And here's a link to the deployed version: <a target="_blank" href="https://next-image-gallery.vercel.app/">https://next-image-gallery.vercel.app/</a>.</p>
<h4 id="heading-what-concepts-amp-topics-will-we-cover-in-this-article">What concepts &amp; topics will we cover in this article?</h4>
<ul>
<li>How to install and use <a target="_blank" href="https://chakra-ui.com/">Chakra UI v1</a> with <a target="_blank" href="https://nextjs.org/">Next.js</a></li>
<li>How to fetch data in Next.js from <a target="_blank" href="https://www.pexels.com/api/">an API</a></li>
<li>How to use the <a target="_blank" href="https://nextjs.org/docs/basic-features/image-optimization">Next.js Image Component</a></li>
<li>How to setup <a target="_blank" href="https://nextjs.org/docs/routing/dynamic-routes">Dynamic Routes</a> in Next.js</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></li>
<li><a class="post-section-overview" href="#heading-how-to-setup-and-install-nextjs">How to Setup and Install Next.js</a></li>
<li><a class="post-section-overview" href="#heading-how-to-generate-the-pexels-api-key">How to Generate the Pexels API Key</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-a-heading-to-the-gallery">How to Add a Heading to the Gallery</a></li>
<li><a class="post-section-overview" href="#heading-how-to-fetch-data-from-the-pexels-api">How to Fetch Data from the Pexels API</a></li>
<li><a class="post-section-overview" href="#heading-how-to-display-photos-on-the-page">How to Display Photos on the Page</a></li>
<li><a class="post-section-overview" href="#heading-how-to-style-images-with-chakra-ui">How to Style Images with Chakra UI</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-search-functionality-to-the-gallery">How to Add Search Functionality to the Gallery</a></li>
<li><a class="post-section-overview" href="#heading-how-to-add-dynamic-routes-to-images">How to Add Dynamic Routes to Images</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<p>Now let's get started.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>Before we get started, you should have:</p>
<ol>
<li>Knowledge of <a target="_blank" href="https://www.freecodecamp.org/learn/responsive-web-design/">HTML, CSS, and JavaScript</a>.</li>
<li>Basic knowledge of <a target="_blank" href="https://www.freecodecamp.org/learn/front-end-libraries/react/">React</a> and Next.js.</li>
<li><a target="_blank" href="https://nodejs.org/en/">Node</a> and NPM installed on your local dev machine.</li>
<li>Any code editor of your choice.</li>
<li><a target="_blank" href="https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en">React Dev Tools</a> (optional)</li>
</ol>
<p>If you feel like your progress is hindered because you don't know enough about these subjects, check out <a target="_blank" href="https://www.freecodecamp.org/learn">https://www.freecodecamp.org/learn</a>. The awesome modules there will get you started in no time.</p>
<h2 id="heading-how-to-setup-and-install-nextjs">How to Setup and Install Next.js</h2>
<p>We will use <a target="_blank" href="https://nextjs.org/docs/api-reference/create-next-app">Create Next App</a> to initialize a Next.js project quickly. In your project's root directory, run the following commands in the terminal.</p>
<pre><code class="lang-bash">npx create-next-app next-image-gallery
<span class="hljs-built_in">cd</span> next-image-gallery
npm run dev
</code></pre>
<p>The last command, <code>npm run dev</code>, will start the development server on your system's port 3000. </p>
<p>Navigate to <a target="_blank" href="http://localhost:3000/">http://localhost:3000</a> in the browser. Here is what your app will look like.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-26.png" alt="Image" width="600" height="400" loading="lazy">
<em>Welcome to Next.js - http://localhost:3000</em></p>
<p>Run the following command to install Chakra UI:</p>
<pre><code class="lang-bash">npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion @chakra-ui/icons
</code></pre>
<p>The next step is to clean the sample code generated by <code>create-next-app</code> and configure the project to use Chakra UI. </p>
<ol>
<li>Delete the <code>styles</code> and <code>pages/api</code> folder.</li>
<li>Update your <code>pages/_app.js</code> like this:</li>
</ol>
<pre><code class="lang-jsx"><span class="hljs-comment">// pages/_app.js</span>
<span class="hljs-keyword">import</span> { ChakraProvider } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyApp</span>(<span class="hljs-params">{ Component, pageProps }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ChakraProvider</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Component</span> {<span class="hljs-attr">...pageProps</span>} /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">ChakraProvider</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyApp;
</code></pre>
<ol start="3">
<li>Modify <code>pages/index.js</code> like this:</li>
</ol>
<pre><code class="lang-jsx"><span class="hljs-comment">// pages/index.js</span>
<span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span> NextJS Image Gallery<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</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">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Again head over to <a target="_blank" href="http://localhost:3000/">http://localhost:3000</a>. You will see that the app is blank, but the title has changed to <code>NextJS Image Gallery</code>. </p>
<p>You can now close the development server.</p>
<h2 id="heading-how-to-generate-the-pexels-api-key">How to Generate the Pexels API Key</h2>
<p>We will use the <a target="_blank" href="https://www.pexels.com/api/">Pexels API</a> to fetch images for our Gallery. You will need to create a Pexels API key to authenticate your API requests. The API itself is completely free to use.</p>
<p>You can make as many as 200 requests per hour and 20,000 requests per month to the Pexels API.</p>
<p>Head over to <a target="_blank" href="https://www.pexels.com/join-consumer/">https://www.pexels.com/join-consumer/</a> and create a new account on Pexels.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-28.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create New Account</em></p>
<p>After filling in your details, you will also need to confirm your account before applying for an API key. So check your inbox and confirm your Pexels account.</p>
<p>Navigate to <a target="_blank" href="https://www.pexels.com/api/new/">https://www.pexels.com/api/new/</a> and fill in the details for a new API key and click <strong>Request API Key</strong></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-31.png" alt="Image" width="600" height="400" loading="lazy">
<em>Request API Key</em></p>
<p>Remember to follow the <a target="_blank" href="https://www.pexels.com/api/documentation/#guidelines">API guidelines</a>. Now copy the API key shown on the next page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-32.png" alt="Image" width="600" height="400" loading="lazy">
<em>API Key</em></p>
<p>In your project's root directory, create a new file named <code>.env.local</code> to store this API key securely. Run the following commands to create the file:</p>
<pre><code class="lang-bash">touch .env.local
</code></pre>
<p>Inside this <code>.env.local</code> file, create a new environment variable named <code>PEXELS_API_KEY</code> and paste the API key there.</p>
<pre><code class="lang-env">NEXT_PUBLIC_PEXELS_API_KEY = ''
</code></pre>
<p>Next.js has built-in support for loading environment variables from <code>.env.local</code> into <code>process.env</code>.</p>
<p>By default, all environment variables loaded through <code>.env.local</code> are only available in the Node.js environment. This means that they won't be exposed to the browser. Using the <code>NEXT_PUBLIC_</code> prefix exposes the environment variable to the browser.</p>
<p>You can read more about it <a target="_blank" href="https://nextjs.org/docs/basic-features/environment-variables">here</a>.</p>
<h2 id="heading-how-to-add-a-heading-to-the-gallery">How to Add a Heading to the Gallery</h2>
<p>In this section, we will add a heading to our Gallery.</p>
<p>Import and add the <code>Box</code> component to <code>index.js</code> like this:</p>
<pre><code class="lang-jsx"><span class="hljs-comment">//pages/index.js</span>
<span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;
<span class="hljs-keyword">import</span> { Box } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span> NextJS Image Gallery<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</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">Box</span> <span class="hljs-attr">overflow</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"purple.100"</span> <span class="hljs-attr">minH</span>=<span class="hljs-string">"100vh"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Navigate to <a target="_blank" href="http://localhost:3000/">http://localhost:3000</a>. You will see that your app has a background color of light purple.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-56.png" alt="Image" width="600" height="400" loading="lazy">
<em>Blank Page with light Purple background</em></p>
<p>Here's what we are doing:</p>
<ul>
<li>In Chakra UI, <code>bg</code> is the shorthand prop for <code>background</code> property. By passing <code>bg="purple.100"</code>,  the background of the app changes to light purple.  The number after the color represents the shade of the color where the lightest is <code>50</code>, and the darkest is <code>900</code>.<br>Here is an image from the <a target="_blank" href="https://chakra-ui.com/docs/theming/theme#purple">Chakra UI docs</a> to better illustrate this point.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-57.png" alt="Image" width="600" height="400" loading="lazy">
<em>Shades of Purple</em></p>
<ul>
<li>Setting <code>minH="100vh"</code> makes the app at least 100% of the parent's element height. <code>minH</code> is the shorthand prop for the <code>min-height</code> property.</li>
<li>To get rid of extra scroll bars in case the content overflows the parent element, <code>overflow="hidden"</code> is passed.</li>
</ul>
<p>To add a heading, we will use the <code>Text</code> and <code>Container</code> component available in Chakra UI.</p>
<p> Modify the <code>Box</code> import in <code>index.js</code> like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Box, Container, Text } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
</code></pre>
<p>Now, add the <code>Container</code> component inside the <code>Box</code> component.</p>
<pre><code class="lang-jsx">&lt;Box overflow=<span class="hljs-string">"hidden"</span> bg=<span class="hljs-string">"purple.100"</span> minH=<span class="hljs-string">"100vh"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
&lt;/Box&gt;
</code></pre>
<p>You will see no change in your app, but the <code>Container</code> component has added some horizontal padding in your app, which will be more apparent after adding the <code>Text</code> component.</p>
<p>Add the following code inside the <code>Container</code> component:</p>
<pre><code class="lang-jsx">&lt;Container&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Text</span>
    <span class="hljs-attr">color</span>=<span class="hljs-string">"pink.800"</span>
    <span class="hljs-attr">fontWeight</span>=<span class="hljs-string">"semibold"</span>
    <span class="hljs-attr">mb</span>=<span class="hljs-string">"1rem"</span>
    <span class="hljs-attr">textAlign</span>=<span class="hljs-string">"center"</span>
    <span class="hljs-attr">textDecoration</span>=<span class="hljs-string">"underline"</span>
    <span class="hljs-attr">fontSize</span>=<span class="hljs-string">{[</span>"<span class="hljs-attr">4xl</span>", "<span class="hljs-attr">4xl</span>", "<span class="hljs-attr">5xl</span>", "<span class="hljs-attr">5xl</span>"]}
  &gt;</span>
    NextJS Image Gallery
  <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span></span>
&lt;/Container&gt;
</code></pre>
<p>Let's break down the above code and discuss it.</p>
<ul>
<li><code>color</code>  is used to set the color of the text to <code>pink.900</code>.</li>
<li><code>fontWeight</code> is used to set the thickness of the character.</li>
<li><code>mb</code> is a shorthand prop for <code>margin-bottom</code> and <code>1rem=16px</code>.</li>
<li><code>textAlign="center"</code> aligns the text in the center.</li>
<li><code>textDecoration="underline"</code> adds a line under the text.</li>
<li><code>fontSize</code>, as the name suggests, sets the size of the text.</li>
</ul>
<p>Here is how your app will look:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-58.png" alt="Image" width="600" height="400" loading="lazy">
<em>Heading - NextJS Image Gallery</em></p>
<pre><code class="lang-javascript">xs: <span class="hljs-string">"12px"</span>
<span class="hljs-attr">sm</span>: <span class="hljs-string">"14px"</span>
<span class="hljs-attr">md</span>: <span class="hljs-string">"16px"</span>
<span class="hljs-attr">lg</span>: <span class="hljs-string">"18px"</span>
<span class="hljs-attr">xl</span>: <span class="hljs-string">"20px"</span>
</code></pre>
<p>You might ask why there are four values of <code>fontSize</code> as an array inside curly braces?</p>
<p>The <code>{}</code> are used to tell the JSX parser to interpret the expression within <code>{}</code> as JavaScript. Here, <code>{}</code>  is used to pass an array for <code>fontSize</code>'s value. This array is a shorthand for media queries in Chakra UI.</p>
<p>The values are passed in an array to make the text responsive and change the font size according to the devices – that is, the heading will be larger on the desktop. </p>
<p>Each index of the array corresponds to a specific breakpoint and the property's value. This means that <code>font-size</code> changes according to the breakpoint. You can read more about it <a target="_blank" href="https://chakra-ui.com/docs/features/responsive-styles">here</a>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> breakpoints = {
  <span class="hljs-attr">sm</span>: <span class="hljs-string">"30em"</span>,
  <span class="hljs-attr">md</span>: <span class="hljs-string">"48em"</span>,
  <span class="hljs-attr">lg</span>: <span class="hljs-string">"62em"</span>,
  <span class="hljs-attr">xl</span>: <span class="hljs-string">"80em"</span>,
}
</code></pre>
<p>It follows the "mobile-first" approach, so the first value is for smaller devices, and the last value is for desktop devices.</p>
<p>The above code will generate CSS like this:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.css-px6f4t</span> {
 <span class="hljs-attribute">text-align</span>:center;
 <span class="hljs-attribute">-webkit-text-decoration</span>:underline;
 <span class="hljs-attribute">text-decoration</span>:underline;
 <span class="hljs-attribute">font-size</span>:<span class="hljs-number">2.25rem</span>;
 <span class="hljs-attribute">color</span>:<span class="hljs-number">#702459</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">1rem</span>;
}
<span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">min-width:</span><span class="hljs-number">30em</span>) {
 <span class="hljs-selector-class">.css-px6f4t</span> {
  <span class="hljs-attribute">font-size</span>:<span class="hljs-number">2.25rem</span>;
 }
}
<span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">min-width:</span><span class="hljs-number">48em</span>) {
 <span class="hljs-selector-class">.css-px6f4t</span> {
  <span class="hljs-attribute">font-size</span>:<span class="hljs-number">3rem</span>;
 }
}
<span class="hljs-keyword">@media</span> screen <span class="hljs-keyword">and</span> (<span class="hljs-attribute">min-width:</span><span class="hljs-number">62em</span>) {
 <span class="hljs-selector-class">.css-px6f4t</span> {
  <span class="hljs-attribute">font-size</span>:<span class="hljs-number">3rem</span>;
 }
}
</code></pre>
<p>Here is the side by side difference in heading size as seen in <a target="_blank" href="https://polypane.app/">Polypane</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-61.png" alt="Image" width="600" height="400" loading="lazy">
<em>Polypane</em></p>
<h2 id="heading-how-to-fetch-data-from-the-pexels-api">How to Fetch Data from the Pexels API</h2>
<p>You have generated the API key so let's write the code to fetch data from the API. We will create a separate file and define the functions to fetch data inside it. </p>
<p>In your project's root directory, create a folder named <code>lib</code>. Inside it, create a file named <code>api.js</code>.</p>
<p>Run the following command in the terminal:</p>
<pre><code class="lang-bash">mkdir lib
<span class="hljs-built_in">cd</span> lib
touch api.js
</code></pre>
<p>This is the Pexels API base URL for photos: <a target="_blank" href="https://api.pexels.com/v1/">https://api.pexels.com/v1</a>/.</p>
<p>The Pexels API has three endpoints:</p>
<ul>
<li><code>/curated</code>  to receive real-time photos curated by the Pexels team.</li>
<li><code>/search</code> to search for photos based on a query.</li>
<li><code>/photos/:id</code> to get a single photo from its id.</li>
</ul>
<p>We will use the <code>/curated</code> endpoint to show photos curated by the Pexels team on the app's landing page.</p>
<p>Add the following code to <code>api.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> API_KEY = process.env.NEXT_PUBLIC_PEXELS_API_KEY;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getCuratedPhotos = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(
    <span class="hljs-string">`https://api.pexels.com/v1/curated?page=11&amp;per_page=18`</span>,
    {
      <span class="hljs-attr">headers</span>: {
        <span class="hljs-attr">Authorization</span>: API_KEY,
      },
    }
  );
  <span class="hljs-keyword">const</span> responseJson = <span class="hljs-keyword">await</span> res.json();
  <span class="hljs-keyword">return</span> responseJson.photos;
};
</code></pre>
<p>Let's discuss the above code:</p>
<ul>
<li>We start by creating a variable named <code>API_KEY</code> that accesses the <code>NEXT_PUBLIC_PEXELS_API_KEY</code> environment variable using <code>process.env.</code></li>
<li>Then we create an asynchronous function named <code>getCuratedPhotos()</code> that uses the <code>fetch()</code> method to fetch the data from the API.</li>
<li>If you take a closer look at the fetch URL, you will notice that we have added <code>?page=11&amp;per_page=18</code> after <code>/curated</code> endpoint. These are the optional parameters that you can pass to the <code>/curated</code> endpoint as <a target="_blank" href="https://en.wikipedia.org/wiki/Query_string">query strings</a>. Here <code>page=11</code> means send the 11th page, and <code>per_page=18</code> means that send 18 photos per page. </li>
<li>You can also remove these optional parameters, in which case the API endpoint will send you 15 pictures from the first page. You can get as many as 80 photos in a single request.</li>
<li>The Pexels API key is passed in the <code>Authorization</code> field under the <code>headers</code>.</li>
<li><code>res.json()</code> parses the response in JSON format. </li>
<li><code>responseJson</code> contains fields like the <code>page</code>, <code>per_page</code>, and so on, which are not used by our app. So only the <code>photos</code> field of the response is returned, which looks like this:</li>
</ul>
<pre><code class="lang-javascript">[
  {
    <span class="hljs-attr">id</span>: <span class="hljs-number">4905078</span>,
    <span class="hljs-attr">width</span>: <span class="hljs-number">7952</span>,
    <span class="hljs-attr">height</span>: <span class="hljs-number">5304</span>,
    <span class="hljs-attr">url</span>: <span class="hljs-string">"https://www.pexels.com/photo/ocean-waves-under-blue-sky-4905078/"</span>,
    <span class="hljs-attr">photographer</span>: <span class="hljs-string">"Nick Bondarev"</span>,
    <span class="hljs-attr">photographer_url</span>: <span class="hljs-string">"https://www.pexels.com/@nick-bondarev"</span>,
    <span class="hljs-attr">photographer_id</span>: <span class="hljs-number">2766954</span>,
    <span class="hljs-attr">src</span>: {
      <span class="hljs-attr">original</span>:
        <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg"</span>,
      <span class="hljs-attr">large2x</span>:
        <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;dpr=2&amp;h=650&amp;w=940"</span>,
      <span class="hljs-attr">large</span>:
        <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;h=650&amp;w=940"</span>,
      <span class="hljs-attr">medium</span>:
        <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;h=350"</span>,
      <span class="hljs-attr">small</span>:
        <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;h=130"</span>,
      <span class="hljs-attr">portrait</span>:
        <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;fit=crop&amp;h=1200&amp;w=800"</span>,
      <span class="hljs-attr">landscape</span>:
        <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;fit=crop&amp;h=627&amp;w=1200"</span>,
      <span class="hljs-attr">tiny</span>:
        <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;dpr=1&amp;fit=crop&amp;h=200&amp;w=280"</span>,
    },
    <span class="hljs-attr">liked</span>: <span class="hljs-literal">false</span>,
  },
];
</code></pre>
<p>In the <code>src</code> field we are given many different image formats to choose from. In this tutorial we will use <code>portrait</code>  type images on our landing page. You are free to explore other formats too.</p>
<p>As we develop our app, we will write the functions to search for a photo and get a single photo in <code>api.js</code>. For now, we will use this function to display an image on our landing page or homepage.</p>
<h2 id="heading-how-to-display-photos-on-the-page">How to Display Photos on the Page</h2>
<p>Now that we have created the function to fetch data, let's display them on our page.</p>
<p>First, import the <code>getCuratedPhotos()</code> function in <code>index.js</code>.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;
<span class="hljs-keyword">import</span> { Box, Container, Text } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> {getCuratedPhotos} <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/api"</span>
</code></pre>
<p>We will use the <code>getServerSideProps()</code> function available in Next.js and use the <code>getCuratedPhotos()</code> function inside it to fetch data from Pexels API and inject it in our page. You can read more about <code>getServerSideProps()</code> <a target="_blank" href="https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering">here</a>.</p>
<p>Add the following code at the bottom of your <code>index.js</code> file:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> getCuratedPhotos();
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: {
      data,
    },
  };
}
</code></pre>
<p>The above async function uses <code>getCuratedPhotos()</code> to fetch images from the Pexels API and store it in the <code>data</code> variable. This <code>data</code> variable is made available as a prop in the <code>props</code> property.</p>
<p>This <code>data</code> is available as a prop so add it as an argument in the <code>Home</code> component function.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params">{data}</span>) </span>{
...
}
</code></pre>
<p>Restart your development server, and inside your <code>Home</code> component, <code>console.log</code> this <code>data</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params">{data}</span>) </span>{
  <span class="hljs-built_in">console</span>.log(data)
  <span class="hljs-keyword">return</span> (
 ...
 }
</code></pre>
<p>Head over to <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> and open the console by pressing <code>CTRL + Shift + J</code> in Chrome or <code>CTRL + Shift + K</code> in Firefox.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-73.png" alt="Image" width="600" height="400" loading="lazy">
<em>console.log(data)</em></p>
<p>Remove the <code>console.log</code> and add the following code to the top of your <code>index.js</code> file to import the <code>useState()</code> hook from <code>react</code>.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
</code></pre>
<p>We will store the data from the Pexels API inside a state named <code>photos</code>. Add the following code before the return statement:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> [photos, setPhotos] = useState(data);
</code></pre>
<p>To display images, map over the <code>photos</code> array and pass <code>src.original</code> in the <code>src</code> attribute of the <code>img</code> element. </p>
<p>Add the following code after the <code>Container</code> component:</p>
<pre><code class="lang-jsx">{
  photos.map(<span class="hljs-function">(<span class="hljs-params">pic</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{pic.src.original}</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"500"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"500"</span> /&gt;</span></span>
  ))
}
</code></pre>
<p>Your app will now look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-74.png" alt="Image" width="600" height="400" loading="lazy">
<em>Displaying images using img element</em></p>
<p>Aside from the fact that the images are not properly sized, there is another issue with us using <code>&lt;img&gt;</code> to display the images.</p>
<p>Head over to <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> and open <strong>Developer tools</strong> and then the <strong>Network</strong> tab ( <strong>Ctrl+ Shift + E</strong> in Firefox and <strong>Ctrl + Shift + J</strong> in Chrome). It will look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-75.png" alt="Image" width="600" height="400" loading="lazy">
<em>Network tab</em></p>
<p>Now reload your page. You will see that the empty <strong>Network</strong> tab is now filled with data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-76.png" alt="Image" width="600" height="400" loading="lazy">
<em>Single request</em></p>
<p>As you can see in the above image, the requested file is sized over 11 MB, and this is for a single file or image. The sizes can vary anywhere from 10 to 100 MB or more based on the quality of the image.</p>
<p>Imagine you have 80 images on your app's landing page. Does it make sense to transfer around 800 MB of files every time someone visits your Gallery or website? <strong>It does not.</strong></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-77.png" alt="Image" width="600" height="400" loading="lazy">
<em>Multiple requests</em></p>
<p>This is why today, most of the images on the web are served in <a target="_blank" href="https://en.wikipedia.org/wiki/WebP">WebP</a> format. This format significantly <strong>reduces the size</strong> of the image, and you can <strong>hardly detect any visual difference</strong>. </p>
<p>So, we need to change the image format to <code>webp</code>, but the question is, how? Do you need to do it manually? If yes, won't it be time consuming and tiresome?</p>
<p><strong>No, you don't need to do it manually.</strong> </p>
<p><a target="_blank" href="https://nextjs.org/blog/next-10">Next.js version 10</a> comes with built-in support for Image Optimization using the <strong>Image</strong> component. You can read more about this update <a target="_blank" href="https://nextjs.org/blog/next-10#built-in-image-component-and-automatic-image-optimization">here</a>.</p>
<p>So, let's replace the <code>img</code> element with the Next.js <code>Image</code> component. First, import this component inside your <code>index.js</code> like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
</code></pre>
<p>But wait, before we use this component in our code, we need to tell Next.js that our images are coming from an external resource, like from Pexels.</p>
<p>Stop your development server and create a <code>next.config.js</code> file by running the following command:</p>
<pre><code class="lang-bash">touch next.config.js
</code></pre>
<p>Add the following code to <code>next.config.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">images</span>: {
    <span class="hljs-attr">domains</span>: [<span class="hljs-string">"images.pexels.com"</span>],
  },
};
</code></pre>
<p>And that's it. There are other configurations like <code>path</code>, <code>imageSizes</code>, <code>deviceSizes</code>, and so on that you can add in the <code>images</code> field. But in this tutorial, we will leave them as default. You can read more about the configuration <a target="_blank" href="https://nextjs.org/docs/basic-features/image-optimization">here</a>.</p>
<p>Replace <code>img</code> with the <code>Image</code> component and pass the props, as shown below: </p>
<pre><code class="lang-jsx">{
  photos.map(<span class="hljs-function">(<span class="hljs-params">pic</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
      <span class="hljs-attr">src</span>=<span class="hljs-string">{pic.src.portrait}</span>
      <span class="hljs-attr">height</span>=<span class="hljs-string">{600}</span>
      <span class="hljs-attr">width</span>=<span class="hljs-string">{400}</span>
      <span class="hljs-attr">alt</span>=<span class="hljs-string">{pic.url}</span>
    /&gt;</span></span>
  ))
}
</code></pre>
<p>As discussed above, the Pexels API provides different formats or sizes of the same image, like <code>portrait</code>, <code>landscape</code>, <code>tiny</code>, and so on, under the <code>src</code> field. </p>
<p>This tutorial uses the <code>portrait</code> images on the landing page, but you are free to explore other sizes. </p>
<pre><code class="lang-javascript">src: {
    <span class="hljs-attr">original</span>: <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg"</span>,
    <span class="hljs-attr">large2x</span>: <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;dpr=2&amp;h=650&amp;w=940"</span>,
    <span class="hljs-attr">large</span>: <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;h=650&amp;w=940"</span>,
    <span class="hljs-attr">medium</span>: <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;h=350"</span>,
    <span class="hljs-attr">small</span>: <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;h=130"</span>,
    <span class="hljs-attr">portrait</span>: <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;fit=crop&amp;h=1200&amp;w=800"</span>,
    <span class="hljs-attr">landscape</span>: <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;fit=crop&amp;h=627&amp;w=1200"</span>,
    <span class="hljs-attr">tiny</span>: <span class="hljs-string">"https://images.pexels.com/photos/4905078/pexels-photo-4905078.jpeg?auto=compress&amp;cs=tinysrgb&amp;dpr=1&amp;fit=crop&amp;h=200&amp;w=280"</span>,
  }
</code></pre>
<p>As you can see in the above sample <code>src</code> field, the <code>portrait</code> format of the image has a width of <strong>800</strong> and a height of <strong>1200</strong>. But it is too large to show on the webpage, so we will scale it down by dividing it by 2. So <code>600</code> and <code>400</code> are passed in for the height and width of the <code>Image</code> component.</p>
<p>Restart your development server and head over to <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a>. You will see that the app itself looks exactly the same. But this time if you open the <strong>Network</strong> tab and reload the page, you will see something truly magical.</p>
<p>Your images are now in <code>webp</code> format, and their sizes have been reduced.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-121.png" alt="Image" width="600" height="400" loading="lazy">
<em>Network tab</em></p>
<p>The Next.js Image component has also added <a target="_blank" href="https://en.wikipedia.org/wiki/Lazy_loading">lazy loading</a> to images. Here is an example to explain how and why you should use lazy loading if you are unfamiliar with it.</p>
<p>Even though the images are now in <code>webp</code> format, is it necessary to load all the images whenever someone visits your website? And if the visitor just comes and leaves without scrolling, does it make sense to load the images at the bottom of the page?</p>
<p>There is no need to load the images that a user or visitor is not going to see in most situations.</p>
<p>And that's where <strong>Lazy Loading</strong> comes to save the day. It delays the requests to images as to when they are needed or, in this situation, when images come into view. This significantly helps reduce the initial page weight and increases website performance.</p>
<p>If you head over to <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> and scroll through all the images, you will see that the images that are not in the viewport are not loaded initially. But as you scroll down, they are transferred and loaded. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/ezgif.com-video-to-gif-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Lazy Loading</em></p>
<p>By default, the <code>layout</code> prop of the <code>Image</code> component has the value of <code>intrinsic</code>, which means the image will scale the dimensions down for smaller viewports but maintain the original dimensions for larger viewports.</p>
<p>There are many props that you can pass to the <code>Image</code> component to modify this component further. You can read about them <a target="_blank" href="https://nextjs.org/docs/api-reference/next/image">here</a>.</p>
<h2 id="heading-how-to-style-images-with-chakra-ui">How to Style Images with Chakra UI</h2>
<p>To style the images, we will use Chakra UI's <code>Wrap</code> component. </p>
<p><a target="_blank" href="https://chakra-ui.com/docs/layout/wrap">Wrap</a> is a layout component that adds a defined space between its children or images in this scenario. It 'wraps' its children automatically if there is not enough space to fit any child.</p>
<p>Import <code>Wrap</code> and <code>WrapItem</code> from Chakra UI.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { Box, Container, Text, Wrap, WrapItem } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
</code></pre>
<p><code>WrapItem</code> encloses the individual children while <code>Wrap</code> encloses all the <code>WrapItem</code> components.</p>
<p>Modify the expression to display images like this:</p>
<pre><code class="lang-jsx">&lt;Wrap px=<span class="hljs-string">"1rem"</span> spacing={<span class="hljs-number">4</span>} justify=<span class="hljs-string">"center"</span>&gt;
  {photos.map(<span class="hljs-function">(<span class="hljs-params">pic</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Image</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{pic.src.portrait}</span> <span class="hljs-attr">height</span>=<span class="hljs-string">{600}</span> <span class="hljs-attr">width</span>=<span class="hljs-string">{400}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{pic.url}</span> /&gt;</span></span>
  ))}
&lt;/Wrap&gt;
</code></pre>
<p>Here's what's happening in the above code:</p>
<ul>
<li><code>px="1rem"</code> is the shorthand prop for <code>padding-left</code> and <code>padding-right</code>.This adds horizontal padding of 1 rem.</li>
<li><code>spacing={4}</code> applies spacing between each child. This will be seen once each image is wrapped with <code>WrapItem</code>.</li>
<li><code>justify="center"</code> justifies the images in the center. </li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-80.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wrap</em></p>
<p>Now wrap each image with <code>WrapItem</code>. Add the following code inside the JavaScript expression:</p>
<pre><code class="lang-jsx">&lt;Wrap px=<span class="hljs-string">"1rem"</span> spacing={<span class="hljs-number">4</span>} justify=<span class="hljs-string">"center"</span>&gt;
  {photos.map(<span class="hljs-function">(<span class="hljs-params">pic</span>) =&gt;</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">WrapItem</span>
      <span class="hljs-attr">key</span>=<span class="hljs-string">{pic.id}</span>
      <span class="hljs-attr">boxShadow</span>=<span class="hljs-string">"base"</span>
      <span class="hljs-attr">rounded</span>=<span class="hljs-string">"20px"</span>
      <span class="hljs-attr">overflow</span>=<span class="hljs-string">"hidden"</span>
      <span class="hljs-attr">bg</span>=<span class="hljs-string">"white"</span>
      <span class="hljs-attr">lineHeight</span>=<span class="hljs-string">"0"</span>
      <span class="hljs-attr">_hover</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">boxShadow:</span> "<span class="hljs-attr">dark-lg</span>" }}
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Image</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{pic.src.portrait}</span> <span class="hljs-attr">height</span>=<span class="hljs-string">{600}</span> <span class="hljs-attr">width</span>=<span class="hljs-string">{400}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{pic.url}</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">WrapItem</span>&gt;</span></span>
  ))}
&lt;/Wrap&gt;
</code></pre>
<p>Let's discuss the props passed to <code>WrapItem</code> one by one:</p>
<ul>
<li><code>key={pic.id}</code> gives each image a unique key so that React can differentiate between the children or pictures.</li>
<li><code>boxShadow="base"</code> adds shadow to <code>WrapItem</code>.</li>
<li><code>rounded="20px"</code> adds a <code>border-radius</code> of 20px.</li>
<li><code>overflow="hidden"</code> make sure the image doesn't overflow the <code>WrapItem</code> and is seen rounded. </li>
<li><code>bg="white"</code> adds a white background to the <code>WrapItem</code>.</li>
<li><code>lineHeight="0"</code> sets <code>line-height</code> property to zero.</li>
<li><code>_hover={{ boxShadow: "dark-lg" }}</code> changes the <code>boxShadow</code> when you hover over the image. </li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/ezgif.com-video-to-gif-2-.gif" alt="Image" width="600" height="400" loading="lazy">
<em>GIF</em></p>
<p>You will see that <code>spacing={4}</code> has also come into effect since we added <code>WrapItem</code> to images.  </p>
<h2 id="heading-how-to-add-search-functionality-to-the-gallery">How to Add Search Functionality to the Gallery</h2>
<p>The next step is to add a feature to allow users to search for images and show those images to them. For this, we will use the <code>/search</code> endpoint in the Pexels API.</p>
<p>In <code>lib/api.js</code> create a new function <code>getQueryPhotos()</code> to search for images based on the user's search input.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getQueryPhotos = <span class="hljs-keyword">async</span> (query) =&gt; {
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://api.pexels.com/v1/search?query=<span class="hljs-subst">${query}</span>`</span>, {
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-attr">Authorization</span>: API_KEY,
    },
  });
  <span class="hljs-keyword">const</span> responseJson = <span class="hljs-keyword">await</span> res.json();
  <span class="hljs-keyword">return</span> responseJson.photos;
};
</code></pre>
<p>The above function <code>getQueryPhotos()</code> is similar to <code>getCuratedPhotos</code> but here we have added a <code>query</code> parameter to the function and modified the API endpoint to include this <code>query</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-string">`https://api.pexels.com/v1/search?query=<span class="hljs-subst">${query}</span>`</span>
</code></pre>
<p>Import the <code>getQueryPhotos()</code> function in <code>index.js</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { getCuratedPhotos, getQueryPhotos } <span class="hljs-keyword">from</span> <span class="hljs-string">"../lib/api"</span>;
</code></pre>
<p>Now, we will create a form to take user input and search for the same. </p>
<p>We will import and use <code>Input</code>,  <code>IconButton</code>,  <code>InputRightElement</code>, and <code>InputGroup</code> from Chakra UI to create this form.</p>
<p>Modify the Chakra UI import like this and add an import for <code>SearchIcon</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  Box,
  Container,
  Text,
  Wrap,
  WrapItem,
  Input,
  IconButton,
  InputRightElement,
  InputGroup,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> { SearchIcon } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/icons"</span>;
</code></pre>
<p>Add the following code for the input form inside the <code>Container</code> component in <code>index.js</code> file:</p>
<pre><code class="lang-jsx">&lt;InputGroup pb=<span class="hljs-string">"1rem"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Input</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search for Apple"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"ghost"</span> /&gt;</span></span>

  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">InputRightElement</span>
    <span class="hljs-attr">children</span>=<span class="hljs-string">{</span>
      &lt;<span class="hljs-attr">IconButton</span>
        <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Search"</span>
        <span class="hljs-attr">icon</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">SearchIcon</span> /&gt;</span>}
        bg="pink.400"
        color="white"
      /&gt;
    }
  /&gt;</span>
&lt;/InputGroup&gt;
</code></pre>
<p>Here's what we are doing.</p>
<ul>
<li><code>InputGroup</code> is used to group the <code>Input</code> and <code>InputRightElement</code> components. Here <code>pb</code> is shorthand for <code>padding-bottom</code>.</li>
<li><code>Input</code> is the input field where users will type their queries. It has a placeholder of "Search for Apple".</li>
<li><code>InputRightElement</code> is used to add an element to the right of the <code>Input</code> component. An <a target="_blank" href="https://chakra-ui.com/docs/form/icon-button">icon button</a> with the icon of search is passed to the <code>children</code> prop of <code>InputRightElement</code>.</li>
<li><code>IconButton</code> is a component in Chakra UI which is useful when you want an icon as a button. The icon to render is passed inside the <code>icon</code> prop.</li>
</ul>
<p>Here's how the input field will look.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-89.png" alt="Image" width="600" height="400" loading="lazy">
<em>Input field</em></p>
<p>This form doesn't do anything yet. Let's change that. </p>
<p>Define a new state named <code>query</code> to store a user's inputs:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params">{ data }</span>) </span>{
  <span class="hljs-keyword">const</span> [photos, setPhotos] = useState(data);
  <span class="hljs-keyword">const</span> [query, setQuery] = useState(<span class="hljs-string">""</span>);

...
}
</code></pre>
<p>Modify the <code>Input</code> component to create a two-way bind between the input field and <code>query</code> state using the <code>value</code> method and <code>onChange</code> event:</p>
<pre><code class="lang-jsx">&lt;Input
  placeholder=<span class="hljs-string">"Search for Apple"</span>
  variant=<span class="hljs-string">"ghost"</span>
  value={query}
  onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> setQuery(e.target.value)}
/&gt;
</code></pre>
<p>Now, create a function named <code>handleSubmit()</code> to handle the click event of search icon. For now we will just <code>console.log</code> the input query and clear the field afterwards.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params">{ data }</span>) </span>{
  <span class="hljs-keyword">const</span> [photos, setPhotos] = useState(data);
  <span class="hljs-keyword">const</span> [query, setQuery] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
    <span class="hljs-keyword">await</span> e.preventDefault();
    <span class="hljs-keyword">await</span> <span class="hljs-built_in">console</span>.log(query);
    <span class="hljs-keyword">await</span> setQuery(<span class="hljs-string">""</span>);
  };

...
}
</code></pre>
<p>Add this function to the <code>onClick</code> event of <code>IconButton</code>:</p>
<pre><code class="lang-jsx">&lt;InputRightElement
  children={
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">IconButton</span>
      <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Search"</span>
      <span class="hljs-attr">icon</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">SearchIcon</span> /&gt;</span>}
      onClick={handleSubmit}
      bg="pink.400"
      color="white"
    /&gt;</span>
  }
/&gt;
</code></pre>
<p>Head over to <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> and type something in the input field and click the search button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-90.png" alt="Image" width="600" height="400" loading="lazy">
<em>console.log(query)</em></p>
<p>But this form is still missing something: if you try to search for something by hitting <strong>Enter</strong> instead of the search button, it will refresh the page, and the query is not logged.</p>
<p>To fix this, enclose the <code>InputGroup</code> with the <code>form</code> element and pass the <code>handleSubmit</code> function to the <code>onSubmit</code> event like this:</p>
<pre><code class="lang-jsx">&lt;form onSubmit={handleSubmit}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">InputGroup</span> <span class="hljs-attr">pb</span>=<span class="hljs-string">"1rem"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Input</span>
      <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search for Apple"</span>
      <span class="hljs-attr">variant</span>=<span class="hljs-string">"ghost"</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{query}</span>
      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setQuery(e.target.value)}
    /&gt;

    <span class="hljs-tag">&lt;<span class="hljs-name">InputRightElement</span>
      <span class="hljs-attr">children</span>=<span class="hljs-string">{</span>
        &lt;<span class="hljs-attr">IconButton</span>
          <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Search"</span>
          <span class="hljs-attr">icon</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">SearchIcon</span> /&gt;</span>}
          onClick={handleSubmit}
          bg="pink.400"
          color="white"
        /&gt;
      }
    /&gt;
  <span class="hljs-tag">&lt;/<span class="hljs-name">InputGroup</span>&gt;</span></span>
&lt;/form&gt;
</code></pre>
<p>You will notice hitting <strong>Enter</strong> will work now.</p>
<p>Now update the <code>handleSubmit</code> function like this to fetch the images based on the user's query:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
  <span class="hljs-keyword">await</span> e.preventDefault();
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> getQueryPhotos(query);
  <span class="hljs-keyword">await</span> setPhotos(res);
  <span class="hljs-keyword">await</span> setQuery(<span class="hljs-string">""</span>);
}
</code></pre>
<p>The above function passes the <code>query</code> variable to the <code>getQueryPhotos()</code> function and the data returned from the function overrides the previous value in the <code>photos</code> variable using <code>setPhotos(res)</code>.</p>
<p>And it's done! You can now search images in your app.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/ezgif.com-video-to-gif-2.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Searching for Apple</em></p>
<p>There's still something missing. What is it?</p>
<p>What if the user tries to search without any query, like with <strong>empty strings</strong>? The current code will still try to make request using <code>""</code> and we will run into the following error.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-91.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To handle this issue, we will use <code>Toast</code> from Chakra UI.</p>
<p>Import <code>useToast</code> from Chakra UI:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> {
  Box,
  Container,
  Text,
  Wrap,
  WrapItem,
  Input,
  IconButton,
  InputRightElement,
  InputGroup,
  useToast
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
</code></pre>
<p>Add the following code jut below where you defined states to intialize Toast.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params">{ data }</span>) </span>{
  <span class="hljs-keyword">const</span> [photos, setPhotos] = useState(data);
  <span class="hljs-keyword">const</span> [query, setQuery] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> toast = useToast();

...
}
</code></pre>
<p>Modify the <code>handleSubmit()</code> function like this:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-keyword">async</span> (e) =&gt; {
  <span class="hljs-keyword">await</span> e.preventDefault();
  <span class="hljs-keyword">if</span> (query == <span class="hljs-string">""</span>) {
    toast({
      <span class="hljs-attr">title</span>: <span class="hljs-string">"Error."</span>,
      <span class="hljs-attr">description</span>: <span class="hljs-string">"Empty Search"</span>,
      <span class="hljs-attr">status</span>: <span class="hljs-string">"error"</span>,
      <span class="hljs-attr">duration</span>: <span class="hljs-number">9000</span>,
      <span class="hljs-attr">isClosable</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">position</span>: <span class="hljs-string">"top"</span>,
    });
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> getQueryPhotos(query);
    <span class="hljs-keyword">await</span> setPhotos(res);
    <span class="hljs-keyword">await</span> setQuery(<span class="hljs-string">""</span>);
  }
};
</code></pre>
<p>In the above code, we check if the <code>query</code> is empty or not with a simple <code>if/else</code> statement. And if it is empty, then we display an error toast with <code>Empty Search</code> text.</p>
<p>Try hitting <strong>Enter</strong> without typing anything in the input field. You will see a toast like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-92.png" alt="Image" width="600" height="400" loading="lazy">
<em>Empty Search toast</em></p>
<h2 id="heading-how-to-add-dynamic-routes-to-images">How to Add Dynamic Routes to Images</h2>
<p>We will create a dynamic route for each image so users can click on images to get more information on them.</p>
<p>Next.js has a very cool feature where you can create a dynamic route by adding brackets to a page (<code>[param]</code>), where <code>param</code> can be URL slugs, pretty URLs, an ID, and so on.</p>
<p>Here the <code>param</code> is <code>id</code>, since to get a specific photo from Pexels API you need to provide its <code>id</code>. </p>
<p>Run the following commands in your project's root directory to create <code>[id].js</code> in the <code>photos</code> directory under pages. </p>
<pre><code class="lang-bash">mkdir pages/photos
<span class="hljs-built_in">cd</span> pages/photos
touch [id].js
</code></pre>
<p>Import <code>Link</code> from <code>next/link</code> in <code>index.js</code>. <code>Link</code> helps in client-side transitions between routes. You can read more about <code>Link</code> <a target="_blank" href="https://nextjs.org/docs/api-reference/next/link">here</a>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>
</code></pre>
<p>Add this <code>Link</code> to each image like this:</p>
<pre><code class="lang-jsx">&lt;Link href={<span class="hljs-string">`/photos/<span class="hljs-subst">${pic.id}</span>`</span>}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Image</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{pic.src.portrait}</span> <span class="hljs-attr">height</span>=<span class="hljs-string">{600}</span> <span class="hljs-attr">width</span>=<span class="hljs-string">{400}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">{pic.url}</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></span>
&lt;/Link&gt;
</code></pre>
<p>Head over to your app and try clicking any image. It will show an error since we have created <code>photos/[id].js</code> but didn't add any code in it. </p>
<p>But if you notice the URL of this page, it will be something like this:</p>
<pre><code>http:<span class="hljs-comment">//localhost:3000/photos/2977079</span>
</code></pre><p>We will now create a third function named <code>getPhotoById()</code> in <code>lib/api.js</code> to get a specific photo based on its id.</p>
<p>Add the following code to <code>api.js</code>:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getPhotoById = <span class="hljs-keyword">async</span> (id) =&gt; {
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://api.pexels.com/v1/photos/<span class="hljs-subst">${id}</span>`</span>, {
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-attr">Authorization</span>: API_KEY,
    },
  });
  <span class="hljs-keyword">const</span> responseJson = <span class="hljs-keyword">await</span> res.json();
  <span class="hljs-keyword">return</span> responseJson;
};
</code></pre>
<p>The above code uses the <code>/photos</code> endpoint to get a single image from Pexels API. You will notice that unlike <code>getCuratedPhotos</code> and <code>getQueryPhotos</code>, <code>getPhotoById</code> returns the <code>responseJson</code> and not <code>responseJson.photos</code>.</p>
<p>Add the following code to <code>photos/[id].js</code>:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> { getPhotoById } <span class="hljs-keyword">from</span> <span class="hljs-string">"../../lib/api"</span>;
<span class="hljs-keyword">import</span> {
  Box,
  Divider,
  Center,
  Text,
  Flex,
  Spacer,
  Button,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/react"</span>;
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"next/image"</span>;
<span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">"next/head"</span>;
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">"next/link"</span>;
<span class="hljs-keyword">import</span> { InfoIcon, AtSignIcon } <span class="hljs-keyword">from</span> <span class="hljs-string">"@chakra-ui/icons"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Photos</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">Box</span> <span class="hljs-attr">p</span>=<span class="hljs-string">"2rem"</span> <span class="hljs-attr">bg</span>=<span class="hljs-string">"gray.200"</span> <span class="hljs-attr">minH</span>=<span class="hljs-string">"100vh"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Image<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</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">Box</span>&gt;</span></span>
    )
  }
</code></pre>
<p>We have added a background color of light gray using the <code>bg</code> prop and <code>Box</code> component. To save time, we have imported all the components and icons beforehand.</p>
<p>Create a <code>getServerSideProps()</code> function in <code>[id].js</code> to fetch data from the Pexels API.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params">{ params }</span>) </span>{
  <span class="hljs-keyword">const</span> pic = <span class="hljs-keyword">await</span> getPhotoById(params.id);
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: {
      pic,
    },
  };
}
</code></pre>
<p>Restart your development server.</p>
<p>You might ask how <code>getServerSideProps()</code> is getting the <code>id</code> of the image from the <code>params</code> argument? </p>
<p>Since this page uses a dynamic route, <code>params</code> contain the route parameters. Here the page name is <code>[id].js</code> , so <code>params</code> will look like <code>{ id: ... }</code>. </p>
<p>You can try <code>console.log(params)</code> – it will look something like this.</p>
<pre><code class="lang-javascript">{ <span class="hljs-attr">id</span>: <span class="hljs-string">'4956064'</span> }
</code></pre>
<p>Pass this <code>pic</code> prop to the <code>Photos</code> component function as an argument.</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Photos</span>(<span class="hljs-params">{ pic }</span>) </span>{
...
}
</code></pre>
<p>Add the following code to the <code>Box</code> component:</p>
<pre><code class="lang-jsx">&lt;Box p=<span class="hljs-string">"2rem"</span> bg=<span class="hljs-string">"gray.200"</span> minH=<span class="hljs-string">"100vh"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span> Image: {pic.id}<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Head</span>&gt;</span></span>

  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Flex</span> <span class="hljs-attr">px</span>=<span class="hljs-string">"1rem"</span> <span class="hljs-attr">justify</span>=<span class="hljs-string">"center"</span> <span class="hljs-attr">align</span>=<span class="hljs-string">"center"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Text</span>
      <span class="hljs-attr">letterSpacing</span>=<span class="hljs-string">"wide"</span>
      <span class="hljs-attr">textDecoration</span>=<span class="hljs-string">"underline"</span>
      <span class="hljs-attr">as</span>=<span class="hljs-string">"h2"</span>
      <span class="hljs-attr">fontWeight</span>=<span class="hljs-string">"semibold"</span>
      <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"xl"</span>
      <span class="hljs-attr">as</span>=<span class="hljs-string">"a"</span>
      <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>
      <span class="hljs-attr">href</span>=<span class="hljs-string">{pic.photographer_url}</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">AtSignIcon</span> /&gt;</span>
      {pic.photographer}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Text</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Spacer</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">as</span>=<span class="hljs-string">"a"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{pic.url}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">InfoIcon</span> <span class="hljs-attr">focusable</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">boxSize</span>=<span class="hljs-string">"2rem"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"red.500"</span> /&gt;</span>{" "}
    <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>{" "}
    <span class="hljs-tag">&lt;<span class="hljs-name">Spacer</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{</span>`/`} &gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
            <span class="hljs-attr">as</span>=<span class="hljs-string">"a"</span>
            <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"full"</span>
            <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"pink"</span>
            <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"lg"</span>
            <span class="hljs-attr">size</span>=<span class="hljs-string">"lg"</span>
            <span class="hljs-attr">cursor</span>=<span class="hljs-string">"pointer"</span>
          &gt;</span>
            🏠 Home
         <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Flex</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Divider</span> <span class="hljs-attr">my</span>=<span class="hljs-string">"1rem"</span> /&gt;</span></span>

  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Center</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">as</span>=<span class="hljs-string">"a"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{pic.url}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
        <span class="hljs-attr">src</span>=<span class="hljs-string">{pic.src.original}</span>
        <span class="hljs-attr">width</span>=<span class="hljs-string">{pic.width</span> / <span class="hljs-attr">4</span>}
        <span class="hljs-attr">height</span>=<span class="hljs-string">{pic.height</span> / <span class="hljs-attr">4</span>}
        <span class="hljs-attr">quality</span>=<span class="hljs-string">{50}</span>
        <span class="hljs-attr">priority</span>
        <span class="hljs-attr">loading</span>=<span class="hljs-string">"eager"</span>        
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Center</span>&gt;</span></span>
&lt;/Box&gt;
</code></pre>
<p>Here is how your page will look now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-99.png" alt="Image" width="600" height="400" loading="lazy">
<em>Photo page</em></p>
<p>Let's break this code down piece by piece.</p>
<ul>
<li>We first modify the title of the page, by passing the id of the image after the <code>Image</code> text.</li>
</ul>
<pre><code class="lang-jsx">&lt;Head&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span> Image: {pic.id}<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"icon"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/favicon.ico"</span> /&gt;</span></span>
&lt;/Head&gt;
</code></pre>
<ul>
<li>We then create a navbar using the <code>Flex</code> component.</li>
</ul>
<pre><code class="lang-jsx">&lt;Flex px=<span class="hljs-string">"1rem"</span> justify=<span class="hljs-string">"center"</span> align=<span class="hljs-string">"center"</span>&gt;
...
&lt;/Flex&gt;
</code></pre>
<p>Here <code>px</code> is shorthand prop for <code>padding-left</code> and <code>padding-right</code>, and <code>justify</code> and <code>align</code> are for <code>justify-content</code> and <code>align-items</code>, respectively.</p>
<ul>
<li>We then add a link to the photographer using the <code>Text</code> and <code>AtSignIcon</code> icons. You can also use the <code>@</code> sign instead of <code>AtSignIcon</code>.</li>
</ul>
<pre><code class="lang-jsx">&lt;Text
  letterSpacing=<span class="hljs-string">"wide"</span>
  textDecoration=<span class="hljs-string">"underline"</span>
  <span class="hljs-keyword">as</span>=<span class="hljs-string">"h2"</span>
  fontWeight=<span class="hljs-string">"semibold"</span>
  fontSize=<span class="hljs-string">"xl"</span>
  <span class="hljs-keyword">as</span>=<span class="hljs-string">"a"</span>
  target=<span class="hljs-string">"_blank"</span>
  href={pic.photographer_url}
&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">AtSignIcon</span> /&gt;</span></span>
  {pic.photographer}
&lt;/Text&gt;
</code></pre>
<p>The <code>as</code> prop is a feature in Chakra UI that allows you to pass an HTML tag or component to be rendered. </p>
<p>Here we are using it with the  <code>&lt;a&gt;</code> tag so the <code>Text</code> component will be rendered as <code>&lt;a&gt;</code> tag on the page. </p>
<p>The <code>target="_blank"</code> makes sure that the link opens in a new window or tab.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-94.png" alt="Image" width="600" height="400" loading="lazy">
<em>Photographer link</em></p>
<ul>
<li>Then we add a <code>Spacer</code> component that, when used with <code>Flex</code>, distributes the empty space between Flex's children. You can read more about it <a target="_blank" href="https://next.chakra-ui.com/docs/layout/flex#flex-and-spacer-vs-grid-vs-stack">here</a>.</li>
</ul>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-96.png" alt="Image" width="600" height="400" loading="lazy">
<em><a target="_blank" href="https://next.chakra-ui.com/docs/layout/flex#flex-and-spacer-vs-grid-vs-stack">Image Source - Chakra UI docs</a></em></p>
<ul>
<li>Next, we add an information icon that links to the photo on Pexels.</li>
</ul>
<pre><code class="lang-jsx">&lt;Box <span class="hljs-keyword">as</span>=<span class="hljs-string">"a"</span> target=<span class="hljs-string">"_blank"</span> href={pic.url}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">InfoIcon</span> <span class="hljs-attr">focusable</span>=<span class="hljs-string">"true"</span> <span class="hljs-attr">boxSize</span>=<span class="hljs-string">"2rem"</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"red.500"</span> /&gt;</span></span>
&lt;/Box&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Spacer</span> /&gt;</span></span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-97.png" alt="Image" width="600" height="400" loading="lazy">
<em>Info Icon</em></p>
<ul>
<li>Then we add <code>Home</code> button in the nav to take the user back to the landing page of the app using the <code>Link</code> component from <code>next/link</code>.</li>
</ul>
<pre><code class="lang-jsx">&lt;Link href={<span class="hljs-string">`/`</span>}&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Button</span>
    <span class="hljs-attr">as</span>=<span class="hljs-string">"a"</span>
    <span class="hljs-attr">borderRadius</span>=<span class="hljs-string">"full"</span>
    <span class="hljs-attr">colorScheme</span>=<span class="hljs-string">"pink"</span>
    <span class="hljs-attr">fontSize</span>=<span class="hljs-string">"lg"</span>
    <span class="hljs-attr">size</span>=<span class="hljs-string">"lg"</span>
    <span class="hljs-attr">cursor</span>=<span class="hljs-string">"pointer"</span>
  &gt;</span>
    🏠 Home
  <span class="hljs-tag">&lt;/<span class="hljs-name">Button</span>&gt;</span></span>
&lt;/Link&gt;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/image-98.png" alt="Image" width="600" height="400" loading="lazy">
<em>Home button</em></p>
<ul>
<li>Then we use <code>Divider</code> component to divide the navbar and the image.</li>
</ul>
<pre><code class="lang-jsx">&lt;Divider my=<span class="hljs-string">"1rem"</span> /&gt;
</code></pre>
<p>Here <code>my</code> is shorthand prop for <code>margin-top</code> and <code>margin-bottom</code>.</p>
<ul>
<li>Finally, we add the image to the page using the <code>Center</code> component, which as the name suggests, centers its children.</li>
</ul>
<pre><code class="lang-jsx">&lt;Center&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Box</span> <span class="hljs-attr">as</span>=<span class="hljs-string">"a"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">{pic.url}</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
      <span class="hljs-attr">src</span>=<span class="hljs-string">{pic.src.original}</span>
      <span class="hljs-attr">width</span>=<span class="hljs-string">{pic.width</span> / <span class="hljs-attr">4</span>}
      <span class="hljs-attr">height</span>=<span class="hljs-string">{pic.height</span> / <span class="hljs-attr">4</span>}
      <span class="hljs-attr">priority</span>
      <span class="hljs-attr">quality</span>=<span class="hljs-string">{50}</span>
      <span class="hljs-attr">loading</span>=<span class="hljs-string">"eager"</span>
    /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Box</span>&gt;</span></span>
&lt;/Center&gt;
</code></pre>
<p>In the above code, we use the <code>Box</code> component to add a link to the original image on Pexels using the <code>as</code> prop.</p>
<p>You will also notice that we have passed a few additional props in the <code>Image</code> component.</p>
<ul>
<li><code>src</code>: We are passing the <code>original</code> image this time.</li>
<li>We scale the image by dividing the original width and height by 4.</li>
<li>By passing <code>priority</code>, the image is considered high priority and is <a target="_blank" href="https://web.dev/preload-responsive-images/#preload-overview">preloaded</a>.</li>
<li>By default, the <code>Image</code> component reduces the quality of  optimized images to 75%, but since the image is still too big, we further decrease its quality to 50%, by passing <code>quality={50}</code>.</li>
<li>By default, loading behavior is lazy in the <code>Image</code> component, but here we want the image to be displayed immediately, and hence we pass <code>loading="eager"</code>.</li>
</ul>
<p>Here is the above code in action.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/ezgif.com-optimize.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Next Image Gallery</em></p>
<h2 id="heading-you-did-it">You did it! 🎉</h2>
<p>Congrats 👏 on building this <strong>Next Image Gallery</strong> project.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we learned how to build an Image Gallery with Next.js using the Pexels API and Chakra UI. </p>
<p>We discussed how to install and use Chakra UI v1 in any Next.js project. We also saw how to fetch data from an API and create dynamic routes in Next.js.</p>
<p>Here are some other APIs that you can explore and use in your project:</p>
<ul>
<li><a target="_blank" href="https://unsplash.com/developers">Unsplash API</a></li>
<li><a target="_blank" href="https://pixabay.com/service/about/api/">Pixabay API</a></li>
<li><a target="_blank" href="https://www.flickr.com/services/api/">flickr API</a></li>
<li><a target="_blank" href="https://finalspaceapi.com/">Final Space API</a></li>
</ul>
<p>Here are some additional resources that can be helpful:</p>
<ul>
<li><a target="_blank" href="https://nextjs.org/docs/getting-started">Next.js Docs</a></li>
<li><a target="_blank" href="https://chakra-ui.com/docs/getting-started">Chakra UI Docs</a></li>
<li><a target="_blank" href="https://www.pexels.com/api/documentation/">Pexels API Docs</a></li>
</ul>
<p>Would you like a second part of this tutorial, where we add animations to images using <a target="_blank" href="https://www.framer.com/motion/">Framer Motion</a>? Let me know on <a target="_blank" href="https://twitter.com/noharashutosh">Twitter</a>.</p>
<p>What other projects or tutorials would you like to see? Reach out to me on <a target="_blank" href="https://twitter.com/noharashutosh">Twitter</a>, and I'll cover them in my next article! </p>
<p>If you're inspired to add features yourself, please do share and <a target="_blank" href="https://twitter.com/noharashutosh">tag me</a> – I'd love to hear about them :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Markdown Previewer with React.js ]]>
                </title>
                <description>
                    <![CDATA[ Building actual projects is a great way to learn React and solidify some of its basic principles. So in this post we will be building a simple Markdown Previewer like what you see in the image above. This will be a simple react app which will contain... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-markdown-previewer-with-react-js/</link>
                <guid isPermaLink="false">66ba19afdd645af073e3918a</guid>
                
                    <category>
                        <![CDATA[ markdown ]]>
                    </category>
                
                    <category>
                        <![CDATA[ projects ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh K Singh ]]>
                </dc:creator>
                <pubDate>Tue, 02 Jun 2020 17:48:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/06/markdown-previewer.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Building actual projects is a great way to learn React and solidify some of its basic principles. So in this post we will be building a simple Markdown Previewer like what you see in the image above. This will be a simple react app which will contain a textarea for Markdown input and a preview tab where the converted text will appear.</p>
<p>If you want to jump right into the code, check out the GitHub Repo here: <a target="_blank" href="https://github.com/lelouchB/markdown-previewer/tree/master">https://github.com/lelouchB/markdown-previewer/tree/master</a></p>
<p>And here's a link to the deployed version :<a target="_blank" href="https://markdown-previewer.lelouch-b.now.sh/">https://markdown-previewer.lelouch-b.now.sh/</a>.</p>
<p>Now let's get started.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ol>
<li>Knowledge of HTML, CSS, Javascript and Bootstrap.</li>
<li>Basic knowledge of React.</li>
<li>Node and NPM installed on your local dev machine.</li>
<li>Any code editor of your choice. </li>
</ol>
<p>If you feel like your progress is hindered because you don't know enough about these subjects, check out <a target="_blank" href="https://www.freecodecamp.org/learn">https://www.freecodecamp.org/learn</a>. There are some awesome modules there that will get you started in no time.</p>
<h2 id="heading-setup">Setup</h2>
<p>We will build this app with the help of <code>npx create-react-app</code> . <strong>Create React App</strong> is an officially supported way to create <em>single-page React applications</em>. It offers a modern build setup with no configuration. </p>
<p>In your project directory run the following command in the terminal:</p>
<pre><code>npx create-react-app markdown-previewer
cd markdown-previewer
npm start
</code></pre><p>Then open <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> to see your app.  It will look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/Screenshot_2020-05-30-React-App.png" alt="Image" width="600" height="400" loading="lazy">
<em>http://localhost:3000/</em></p>
<p>Now, let's see the <strong>Project Structure</strong> here:</p>
<pre><code>markdown-previewer
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    └── serviceWorker.js
</code></pre><p>No configuration or complicated folder structures – only the files you need to build your app. </p>
<p>Now, before we proceed further, let's clean up these files:</p>
<ol>
<li>Delete <code>index.css</code> and <code>App.css</code> .</li>
<li>Since we have deleted <code>index.css</code> and <code>App.css</code> , remove <code>import './index.css';</code> and <code>import './App.css';</code>from <code>index.js</code> and <code>App.js</code> respectively.</li>
<li>Delete <code>logo.svg</code> and remove <code>import logo from './logo.svg';</code> in <code>App.js</code>.</li>
<li>Inside <code>App.js</code> remove the function <code>App()</code> . We will export a class component rather than a functional component. So, change  <code>App.js</code> to look like this:</li>
</ol>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">App</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span></span>{
render(){
  <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">div</span>&gt;</span></span>
  );}
}
</code></pre>
<p> Head over to <a target="_blank" href="http://localhost:3000">http://localhost:3000</a> and it will be blank now.</p>
<h2 id="heading-design">Design</h2>
<p>But one more thing before we get into it… It’s always a good idea to have a plan of what you are going to build before you start typing. Especially when you're building a user interface with React. </p>
<p>We want to have some idea of what the interface will look like so we can know what components we need to build and what data each component will be responsible for handling.</p>
<p>So to begin, I have drawn a quick sketch of what the markdown-previewer app will look like. I have also labeled all of the components we will need to create:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-177.png" alt="Image" width="600" height="400" loading="lazy">
<em>Design</em></p>
<p>So it looks like we will need to build three primary components:</p>
<ol>
<li><strong>Title and SubHeading</strong>— This will simply display our headings and subheadings.</li>
<li><strong>Markdown Input TextArea</strong> — This is the input texarea where the markdown we want to preview will be written.</li>
<li><strong>Markdown Preview</strong> — This is a container with a greyish background where the output will display.</li>
</ol>
<h3 id="heading-a-few-things-to-note">A few things to note:</h3>
<ol>
<li>We will have an ‘App’ component that contains everything. This is small project so it is easy to maintain all the components in a single file. But as the size of your project increases (for example, while building an e-Commerce platform), you would have to seperate components into different files and folders by their types. </li>
<li>Since this article is not about CSS and designing, I will use the <a target="_blank" href="https://react-bootstrap.github.io/">React-Bootstrap</a> library and Inline Styles. Any discussion about them will be kept short. </li>
</ol>
<h3 id="heading-inline-styles-in-react">Inline Styles in React</h3>
<p>When using inline styles, it means that instead of making separate CSS files, components are styled by passing the CSS properties as an Object. For example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">var</span> divStyle = {
  <span class="hljs-attr">color</span>: <span class="hljs-string">'white'</span>,
  <span class="hljs-attr">backgroundImage</span>: <span class="hljs-string">'url('</span> + imgUrl + <span class="hljs-string">')'</span>,
  <span class="hljs-attr">WebkitTransition</span>: <span class="hljs-string">'all'</span>, <span class="hljs-comment">// note the capital 'W' here</span>
  <span class="hljs-attr">msTransition</span>: <span class="hljs-string">'all'</span> <span class="hljs-comment">// 'ms' is the only lowercase vendor prefix</span>
};

ReactDOM.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{divStyle}</span>&gt;</span>Hello World!<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>);
</code></pre>
<p>Style keys are camelCased in order to be consistent with accessing the properties on DOM nodes from JS (e.g. <code>node.style.backgroundImage</code>). Vendor prefixes other than <code>ms</code> should begin with a capital letter. This is why <code>WebkitTransition</code> has an uppercase "W".                 </p>
<p>The style object is then passed in the DOM component using <code>{}</code> . We can use run Javascript code inside our <code>return</code> method using <code>{}</code>.</p>
<h2 id="heading-code">Code</h2>
<p>Okay it’s time to start writing code! If at any time you get stuck, feel free to refer to the finished app here: <a target="_blank" href="https://github.com/lelouchB/markdown-previewer/tree/master">https://github.com/lelouchB/markdown-previewer/tree/master</a> and <a target="_blank" href="https://markdown-previewer.lelouch-b.now.sh/">https://markdown-previewer.lelouch-b.now.sh/</a></p>
<h3 id="heading-installing-dependencies">Installing Dependencies</h3>
<p>Let's start by installing our project dependencies. Inside the project directory, run the following commands:</p>
<pre><code>npm install react-bootstrap bootstrap 
npm install marked
</code></pre><p>Now, let's discuss them:</p>
<ol>
<li>The first command installs <a target="_blank" href="https://react-bootstrap.github.io/getting-started/introduction">React-Bootstrap</a> and Bootstrap which we will use to style our project.</li>
<li>The second command installs <a target="_blank" href="https://marked.js.org">Marked.js</a>, which is a low-level markdown compiler for parsing markdown without caching or blocking for long periods of time. This will run the actual logic behind converting the markdown.</li>
</ol>
<p>Before we start using React-Bootstrap inside our project, we will have to add the minified bootstrap CSS file to our <code>index.js</code>:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">'../node_modules/bootstrap/dist/css/bootstrap.min.css'</span>;
</code></pre>
<p>With this the dependencies have been installed and are ready to be used.</p>
<h3 id="heading-headings">Headings</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-178.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Our first task will be to add a heading to our React app and center align it. For that we will use <a target="_blank" href="https://react-bootstrap.github.io/components/badge/">Badge</a>, a component of the React-Bootstrap library. Here are the steps to do that:</p>
<ol>
<li>Import Badge to <code>App.js</code>. Inside <code>App.js</code> add the following:</li>
</ol>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> Badge <span class="hljs-keyword">from</span> <span class="hljs-string">"react-bootstrap/Badge"</span>;
</code></pre>
<ol start="2">
<li>In <code>App.js</code> inside return and under the <code>div</code> with the <code>className="App"</code>,  add another <code>div</code> with the <code>className="container"</code>.</li>
</ol>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Badge <span class="hljs-keyword">from</span> <span class="hljs-string">"react-bootstrap/Badge"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">App</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
  render() {
    <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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>

        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
  }
}
</code></pre>
<ol start="3">
<li>Next inside div with the <code>className="container"</code>,  we will add the heading as follows:</li>
</ol>
<pre><code> &lt;h1&gt;
 <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Badge</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-align-center"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"light"</span>&gt;</span>
 Markdown Previewer
<span class="hljs-tag">&lt;/<span class="hljs-name">Badge</span>&gt;</span></span>
 &lt;/h1&gt;
</code></pre><ol start="4">
<li>You can now see a heading at <a target="_blank" href="http://localhost:3000">http://localhost:3000</a>, but it is not centered. To center the heading we will use bootstrap and enclose the above code block inside two divs.</li>
</ol>
<pre><code>&lt;div className=<span class="hljs-string">"row mt-4"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col text-center"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">Badge</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-align-center"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"light"</span>&gt;</span>
        Markdown Previewer
     <span class="hljs-tag">&lt;/<span class="hljs-name">Badge</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><p>With this we have added a heading to our app.</p>
<h3 id="heading-sub-headings">Sub Headings</h3>
<p>If you look at the design we're discussing above, you'll see that the next step will be to add two columns with the subheadings <strong>Markdown Input</strong> and <strong>Preview.</strong> One will contain the Input TextArea and the other the Preview.</p>
<ol>
<li>First we will have to create two columns placed side by side inside our app. We will do so using bootstrap. Inside the div container, add the following:</li>
</ol>
<pre><code class="lang-js">
&lt;div className=<span class="hljs-string">"row mt-4"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Lorem Ipsum<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>

  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Lorem Ipsum<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/div&gt;;
</code></pre>
<p>I have used Lorem Ipsum for now, and will remove it in the next step. Columns are created using bootstrap classes, and the first <code>div</code> with <code>className="row mt-4"</code> creates a <strong>row</strong>. The <code>m</code> indicates <code>margin</code>. The <code>t</code> indicates <code>top</code>. The other two <code>div</code>s with <code>className="col-md-6"</code> create <strong>two columns</strong>. </p>
<p>The app will now look something like this.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-180.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="2">
<li>The next step will be to add headings to these columns and center align them. This can be done by adding a div with the className="col text-center" inside that Badge, to both the divs with the <code>className="col-md-6"</code>.</li>
</ol>
<pre><code>&lt;div className=<span class="hljs-string">"col text-center"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Badge</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-align-center"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"light"</span>&gt;</span>
    // Actual Sub Heading: This code block will be same for both columns
    <span class="hljs-tag">&lt;/<span class="hljs-name">Badge</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><ol start="3">
<li>Your <code>App.js</code> will now look like this:</li>
</ol>


<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-181.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-textarea">TextArea</h3>
<p>Next we're going to add a TextArea in our app. We will use the simple HTML <code>&lt;textarea&gt;</code> tag to do so.</p>
<ol>
<li>Add another div with the <code>classname="mark-input"</code> and add <code>textarea</code> with <code>className="input"</code> inside it.</li>
</ol>
<pre><code>&lt;div className=<span class="hljs-string">"mark-input"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"input"</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span></span>
&lt;/div&gt;;
</code></pre><ol start="2">
<li>Let's customize TextArea a bit. As discussed above, we will be using Inline Styles, so for that let's fist initailize an <strong>Object</strong>. All the variables will be declared inside the <code>render()</code> function but outside of <code>return</code>. For example, </li>
</ol>
<pre><code>render(){
 <span class="hljs-keyword">var</span> variableOne = <span class="hljs-string">"Lorem Ipsum"</span>
 <span class="hljs-keyword">var</span> variableTwo = <span class="hljs-string">"Lorem Ipsum"</span>

  <span class="hljs-keyword">return</span>(
   <span class="hljs-comment">// Code</span>
   )
}
</code></pre><ol start="3">
<li>Here is the <code>inputStyle</code> object:</li>
</ol>
<pre><code> <span class="hljs-keyword">var</span> inputStyle = {
      <span class="hljs-attr">width</span>: <span class="hljs-string">"400px"</span>,
      <span class="hljs-attr">height</span>: <span class="hljs-string">"50vh"</span>,
      <span class="hljs-attr">marginLeft</span>: <span class="hljs-string">"auto"</span>,
      <span class="hljs-attr">marginRight</span>: <span class="hljs-string">"auto"</span>,
      <span class="hljs-attr">padding</span>:<span class="hljs-string">"10px"</span>
    };
</code></pre><ol start="4">
<li>Let's add the <code>inputStyle</code> object to our <code>textarea</code>:</li>
</ol>
<pre><code>&lt;div className=<span class="hljs-string">"mark-input"</span> style={inputStyle}&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
  <span class="hljs-attr">className</span>=<span class="hljs-string">"input"</span>
  <span class="hljs-attr">style</span>=<span class="hljs-string">{inputStyle}</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span></span>
</code></pre><p>With this we have added TextArea to our App and it will look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-182.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-preview">Preview</h3>
<p>To separate our preview from the rest of the app and to enclose it inside a container, we will follow the above process. We'll create a div inside the second columns and add a style object to it, like this:</p>
<pre><code>  <span class="hljs-keyword">var</span> outputStyle = {
      <span class="hljs-attr">width</span>: <span class="hljs-string">"400px"</span>,
      <span class="hljs-attr">height</span>: <span class="hljs-string">"50vh"</span>,
      <span class="hljs-attr">backgroundColor</span>: <span class="hljs-string">"#DCDCDC"</span>,
      <span class="hljs-attr">marginLeft</span>: <span class="hljs-string">"auto"</span>,
      <span class="hljs-attr">marginRight</span>: <span class="hljs-string">"auto"</span>,
      <span class="hljs-attr">padding</span>:<span class="hljs-string">"10px"</span>
    };
</code></pre><p>Add the object to the <code>div</code> :</p>
<pre><code>&lt;div className=<span class="hljs-string">"col-md-6"</span>&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col text-center"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h4</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Badge</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-align-center"</span> <span class="hljs-attr">variant</span>=<span class="hljs-string">"secondary"</span>&gt;</span>
        Preview
      <span class="hljs-tag">&lt;/<span class="hljs-name">Badge</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{outputStyle}</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/div&gt;
</code></pre><p>Here is how the app will look now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-183.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We now have completed the look of our app, but it is missing its functionality, so let's add that. The process from here can be divided into three steps:</p>
<ol>
<li>Taking input from TextArea.</li>
<li>Passing the input to the Marked.js library and displaying the processed data to the <strong>Preview</strong> column.</li>
</ol>
<h2 id="heading-taking-input-from-textarea">Taking Input from TextArea</h2>
<p>We will use the <code>state</code> object. </p>
<h3 id="heading-statehttpsreactjsorgdocsstate-and-lifecyclehtml"><a target="_blank" href="https://reactjs.org/docs/state-and-lifecycle.html">State</a></h3>
<p>In React, “state” is an object that represents the parts of the app that can change. Each component can maintain its own state, which lives in an object called <code>this.state</code>. The <code>state</code> object is where you store property values that belong to the component.</p>
<p>Simply put, if you’d like your app to <em>do</em> anything – if you want interactivity, adding and deleting things, logging in and out – that will involve state.</p>
<p>Here the <strong>value</strong> of our textarea is changing, and our state will change with it. We'll add the state object inside our <strong>class App</strong>, above the <code>render()</code> function. </p>
<p>It is best practice to  initialize <code>state</code> inside <code>constructor</code>. It can work without <code>constructor</code> also but you should avoid that. Here is how we will initialize it with the property <code>markdown</code> , initially having an empty string:</p>
<pre><code><span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">App</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">React</span>.<span class="hljs-title">Component</span> </span>{
<span class="hljs-keyword">constructor</span>(props){
    <span class="hljs-built_in">super</span>(props)
    <span class="hljs-built_in">this</span>.state = {
      <span class="hljs-attr">markdown</span>: <span class="hljs-string">""</span>,
    };
  }
  render(){
  <span class="hljs-comment">// method and other code</span>
  }
  }
</code></pre><p>In this project or in any other react projects, always initialize <code>state</code> inside <code>constructor(props)</code> and below <code>super(props)</code>.</p>
<p>Typically, in React, constructors are only used for two purposes:</p>
<ul>
<li>Initializing <a target="_blank" href="https://reactjs.org/docs/state-and-lifecycle.html">local state</a> by assigning an object to <code>this.state</code>.</li>
<li>Binding <a target="_blank" href="https://reactjs.org/docs/handling-events.html">event handler</a> methods to an instance.</li>
</ul>
<p>Keep in mind that Constructor is the only place where you should assign <code>this.state</code> directly. In all other methods, you need to use <code>this.setState()</code> instead. </p>
<p>State changes are asynchronous. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.</p>
<p>As discussed above we cannot change state directly. Instead we have to use <code>this.setState()</code> so let's create a method that does that and is called every time the value of textarea is changed.</p>
<pre><code>  updateMarkdown(markdown) {
    <span class="hljs-built_in">this</span>.setState({ markdown });
  }
</code></pre><p>This method is created inside the class component but above the <code>render()</code> function. </p>
<p>But we will first set the value of textarea to the <code>markdown</code>  property in state. </p>
<pre><code>&lt;textarea className=<span class="hljs-string">"input"</span> style={inputStyle} value={<span class="hljs-built_in">this</span>.state.markdown}&gt;&lt;/textarea&gt;
</code></pre><p>Now we can add <code>updateMarkdown()</code> to <code>onChange()</code> event inside <code>&lt;textarea&gt;</code> and call it <code>this.updateMarkdown()</code>.</p>
<pre><code>&lt;textarea
  className=<span class="hljs-string">"input"</span>
  style={inputStyle}
  value={<span class="hljs-built_in">this</span>.state.markdown}
  onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-built_in">this</span>.updateMarkdown(e.target.value);
  }}
&gt;&lt;/textarea&gt;;
</code></pre><p>Next we can check to see if state is assigning properly by passing a Javascript code and <code>console.log()</code> our state.</p>
<pre><code>&lt;textarea
  className=<span class="hljs-string">"input"</span>
  style={inputStyle}
  value={<span class="hljs-built_in">this</span>.state.markdown}
  onChange={<span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-built_in">this</span>.updateMarkdown(e.target.value);
  }}
&gt;
  {<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">this</span>.state.markdown)}
&lt;/textarea&gt;;
</code></pre><p>Now open your console and try writing inside textarea, and hopefully you will see the same being added to the console.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-184.png" alt="Image" width="600" height="400" loading="lazy">
<em>Check</em></p>
<p>With this we have successfully assigned the input of textarea to our state markdown property. Here is how your <code>App.js</code> will look now:</p>


<h2 id="heading-markedjs">Marked.js</h2>
<p>Marked.js is the brains behind the conversion of markdown and is very simple to use.</p>
<p>Importing <code>marked</code>, add the following just below where you imported Badge from <code>react-bootstrap/Badge</code></p>
<pre><code><span class="hljs-keyword">let</span> marked = <span class="hljs-built_in">require</span>(<span class="hljs-string">"marked"</span>);
</code></pre><p>To use the Marked.js library, we just have to pass the string to be converted inside the <code>marked()</code> function. We already have the data dynamically stored inside the state object, so it will be done like this:</p>
<pre><code>marked(<span class="hljs-built_in">this</span>.state.markdown)
</code></pre><p>Now, the next step is to actually display the converted data on the webpage. To do that we will use <code>dangerouslySetInnerHTML</code>, which is an attribute under DOM Elements in React. According to the official documentation:</p>
<blockquote>
<p><code>_dangerouslySetInnerHTML_</code> is React’s replacement for using <code>_innerHTML_</code> in the browser DOM.</p>
</blockquote>
<p>This means that if in React you have to set the HTML <strong>programmatically</strong> or from an <strong>external source</strong>, you will have to use <code>dangerouslySetInnerHTML</code> instead of traditional <code>innerHTML</code> in Javascript.</p>
<p><strong>In simple words using</strong> <code>**dangerouslySetInnerHTML**</code> <strong>you can set HTML directly from React.</strong></p>
<p>While using <code>dangerouslySetInnerHTML</code> , you will have to pass an <strong>object</strong> with a <code>__html</code> key. <strong>(Note the key consists of two underscores.)</strong> </p>
<p>Here is how we will do that:</p>
<pre><code>&lt;div
style={outputStyle}
dangerouslySetInnerHTML={{ <span class="hljs-attr">__html</span>: marked(<span class="hljs-built_in">this</span>.state.markdown) }}
&gt;
&lt;/div&gt;
</code></pre><p>With this we have completed our project and now you will see your <code>Markdown Previewer</code> in action.</p>
<p>Here is the complete <code>App.js</code></p>


<h2 id="heading-we-did-it">We did it! ?</h2>
<p>Congrats on building this React Mardown Previewer.</p>
<h2 id="heading-what-next">What next?</h2>
<p>So, what is the future of this project? You are the future. <strong>Make your own version</strong> of Markdown Previewer, add different designs, layouts, custom functionalities. For example you could add a <strong>Reset Button</strong> to clear the textarea – it's all up to your imagination. I hope you had fun coding along.</p>
<p>What other projects or tutorials would you like to see ? Reach out to me on <a target="_blank" href="https://twitter.com/noharashutosh">Twitter</a>, and I'll make more tutorials! If you're inspired to add features yourself, please do share and <a target="_blank" href="https://twitter.com/noharashutosh">tag me</a> – I'd love to hear about them :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is dllhost.exe and COM Surrogate in Windows Task Manager? (Solved) ]]>
                </title>
                <description>
                    <![CDATA[ COM Surrogate processes, short for Component Object Model, are necessary components in Windows. They are used to run software extensions that other programs need to run. And if those extensions crash, it is the surrogate processes that are affected a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-dllhost-exe-and-com-surrogate-in-windows-task-manager-solved/</link>
                <guid isPermaLink="false">66ba19b243a303ea8f43c0f9</guid>
                
                    <category>
                        <![CDATA[ error handling ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Windows ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh K Singh ]]>
                </dc:creator>
                <pubDate>Tue, 12 May 2020 16:14:45 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9b18740569d1a4ca29a4.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>COM Surrogate processes, short for <strong>Component Object Model</strong>, are necessary components in Windows. They are used to run software extensions that other programs need to run. And if those extensions crash, it is the surrogate processes that are affected and not the programs that were running them.</p>
<p>There are many use cases of these processes, for example creating thumbnails of images and other files when a folder is opened. The COM Surrogate process hosts .dll files, so its name is dllhost.exe.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-172.png" alt="Image" width="600" height="400" loading="lazy">
_Photo by [Unsplash](https://unsplash.com/@christinhumephoto?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit"&gt;Christin Hume / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm<em>campaign=api-credit)</em></p>
<h2 id="heading-is-com-surrogate-a-virus"><strong>Is COM Surrogate a virus?</strong></h2>
<p>The short answer is no. COM Surrogate processes themselves cannot be viruses. However, viruses and malware can disguise themselves as a COM Surrogate process.</p>
<h2 id="heading-should-i-remove-com-surrogate">Should I remove COM Surrogate?</h2>
<p>Since it is an integrated part of Windows, I wouldn't advise you to remove it. This container process enables your OS to run COM objects that help other processes and programs to work.</p>
<h2 id="heading-checking-the-legitimacy-of-com-surrogate">Checking the legitimacy of COM Surrogate</h2>
<p>Since these processes are genuine components of Windows, they are widely used by cybercriminals. This has consequences – like the COM Surrogate having high CPU consumption and creating duplicates in the Task Manager. </p>
<p>A simple way to check its legitimacy is:</p>
<ol>
<li>Open Windows Task Manager by <strong>right-clicking</strong> on the taskbar and clicking Task Manager.</li>
<li>Find the COM Surrogate processes and then right-click to <strong>Open File Location</strong>.</li>
<li>Processes are legitimate if they are located in <strong>C:/Windows\System32</strong> or <strong>C:/winnt/system32</strong>.</li>
</ol>
<h2 id="heading-common-errors">Common Errors</h2>
<ol>
<li><strong>COM Surrogate high CPU, disk usage</strong></li>
<li><strong>COM Surrogate is not responding, freeze</strong></li>
<li><strong>COM Surrogate virus</strong></li>
<li><strong>COM Surrogate taking memory</strong></li>
<li><strong>COM Surrogate always running</strong></li>
<li><strong>COM Surrogate stopped working</strong></li>
<li><strong>COM Surrogate keeps crashing, opening</strong></li>
</ol>
<p>There are many reasons for these errors to occur. The most common are:</p>
<ol>
<li>A third-party program incorrectly registered COM objects or they did not work correctly (if they were incompatible with current versions of Windows, outdated software).</li>
<li>If the problem occurs during drawing thumbnails in Explorer, it's because of outdated or incorrectly working codecs. </li>
<li>Can be caused by viruses or malware, as well as damage to Windows System Files.</li>
</ol>
<h2 id="heading-how-can-you-fix-these-errors">How can you fix these errors?</h2>
<p>We discussed many errors above but the most common of them is "<strong>COM Surrogate has stopped working</strong>". Below are the various methods to resolve it.</p>
<p>And even if you are having any of the other errors listed above, these methods are good to go and should help fix them, too.</p>
<h3 id="heading-1-update-codecs">1. Update Codecs</h3>
<p>A manual method to solve this error is to update all the <strong>Codecs</strong> of Windows (7, 8 or 10) to their latest updated versions. You can download and install your latest <strong>Windows Codec Pack</strong> from here:</p>
<p><a target="_blank" href="https://www.microsoft.com/en-in/download/details.aspx?id=507">https://www.microsoft.com/en-in/download/details.aspx?id=507</a></p>
<p><strong>Windows 7 Codec Pack:</strong> <a target="_blank" href="https://www.windows7codecs.com/">https://www.windows7codecs.com/</a>    </p>
<p><strong>Windows 8 &amp; 10 Codec Pack:</strong> <a target="_blank" href="https://www.windows8codecs.com/">http://www.windows8codecs.com/</a></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-68.png" alt="Image" width="600" height="400" loading="lazy">
<em>Installing Codecs</em></p>
<h3 id="heading-2-reset-internet-explorer"><strong>2. Reset Internet Explorer</strong></h3>
<p>The issue can also be caused due to cached files that were corrupt. In this instance, it's be best to reset IE. </p>
<ol>
<li>Hold the <strong>Windows Key</strong> and <strong>Press R</strong>. In the run dialog, type <strong>inetcpl.cpl</strong> and click <strong>OK.</strong> Go to the Advanced Tab and choose Reset. </li>
<li>Select <strong>Delete Personal Settings</strong> and hit the reset button again. Once you've done all that, reboot your PC and test it out.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-69.png" alt="Image" width="600" height="400" loading="lazy">
<em>Resetting Internet Explorer</em></p>
<h3 id="heading-3-check-disk-for-errors">3. Check Disk For Errors</h3>
<p>If this error occurs when opening files saved in a particular <strong>DRIVE</strong> other then C:\ then you should check that drive for errors. If you don't have any additional drives, just check the C:\ drive.</p>
<ol>
<li>Hold the <strong>Windows Key</strong> and press <strong>E</strong>. On <strong>Windows 7/Vista</strong> you will see the drives listed. </li>
<li>On Windows 8/10, chose <strong>This PC</strong> from the left pane to view the drives. <strong>Right-click</strong> on the Selected <strong>Hard disk drive</strong> that you want to check and then select “<strong>Properties”</strong>.   </li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-67.png" alt="Image" width="600" height="400" loading="lazy">
<em>Checking Disk for Errors</em></p>
<ol start="3">
<li>Click the <strong>Tools</strong> tab from the top and then click <strong>Check Now</strong> under <strong>Error-                  Checking. Check</strong> both the <strong>Options</strong> and the click <strong>Start</strong>.</li>
</ol>
<h3 id="heading-4-re-register-the-dlls">4. Re-register the DLLs</h3>
<ol>
<li>Run the following commands in an escalated command prompt. Click Start, type <strong>cmd,</strong> and right click on the “<strong>cmd</strong>” program from the search results. Then select <strong>Run as Administrator</strong>.</li>
</ol>
<p><img src="https://cdn.appuals.com/wp-content/uploads/2014/11/cmd-run-as-administrator.png" alt="cmd-run-as-administrator" width="405" height="140" loading="lazy">
<em>Running cmd as Administrator</em></p>
<ol start="2">
<li>In the <strong>Command Prompt</strong> window, type the following commands and press the        <strong>Enter key</strong> one by one:</li>
</ol>
<p><code>regsvr32 vbscript.dll</code>
<code>regsvr32.jscript.dll</code></p>
<p><img src="https://cdn.appuals.com/wp-content/uploads/2015/12/2015-12-03_002655.png" alt="2015-12-03_002655" width="608" height="183" loading="lazy">
<em>Re-registering the DLLs</em></p>
<h3 id="heading-5-rollback-to-the-previous-display-adapter-driver">5. Rollback to the Previous Display Adapter Driver</h3>
<ol>
<li>To do this, hold the <strong>Windows Key</strong> and <strong>Press R</strong>. In the run dialog, type <strong>hdwwiz.cpl</strong> and click <strong>OK</strong>. </li>
<li>Scroll to the <strong>Display Adapters</strong> section in the Device Manager. Right click on it and select Properties. </li>
<li>Click <strong>Roll Back Driver</strong> and proceed with the instructions on the screen. </li>
</ol>
<p>In some cases, this option is grayed out. If that is the case then attempt the methods below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-72.png" alt="Image" width="600" height="400" loading="lazy">
<em>Display Adapter</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-71.png" alt="Image" width="600" height="400" loading="lazy">
<em>Roll Back Driver</em></p>
<h3 id="heading-6-add-dllhostexe-to-the-depdata-execution-prevention-exception"><strong>6. Add dllhost.exe to the DEP(Data Execution Prevention) Exception</strong></h3>
<p>Go to Start &gt; Control Panel &gt; System &gt; Advanced System settings&gt; Performance settings &gt; Data Execution Prevention.</p>
<ol>
<li>Select <strong>“</strong>Turn on DEP for all programs and services except those I select:<strong>”</strong></li>
<li>Click on “<strong>Add“</strong> and navigate to <strong>C:\Windows\System32\dllhost.exe on 32-bit Windows Machine</strong> and on a <strong>64-bit machine, add </strong>C:\Windows\SysWOW64\dllhost.exe<em>**</em></li>
<li>After adding <strong>dllhost.exe</strong> to the exception list, <strong>Apply changes</strong> or click <strong>OK.</strong></li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/05/image-73.png" alt="Image" width="600" height="400" loading="lazy">
<em>Data Execution Prevention</em></p>
<h3 id="heading-7-switch-to-list-or-details-view-disable-thumbnails">7. Switch to List or Details view / disable thumbnails</h3>
<p>We have already discussed that <strong>COM Surrogate</strong> is in charge of your thumbnails. In order to avoid problems with it, you can disable thumbnails.</p>
<p>In addition, you can switch to <strong>List</strong> or <strong>Details</strong> view by doing the following:</p>
<ol>
<li>Open <strong>File Explorer</strong>.</li>
<li>Click the <strong>View tab</strong> and choose the <strong>List</strong> or <strong>Details</strong> option.</li>
</ol>
<h3 id="heading-8-update-your-antivirus">8. Update your Antivirus</h3>
<p>It has been reported that certain antivirus software, such as Kaspersky antivirus, can sometimes cause issues with the <strong>COM Surrogate</strong> process.</p>
<p>In order to fix those issues, you should install the latest version of your current antivirus software.</p>
<hr>
<p><em>Thank you for reading this article. I hope it will help you fix your COM Surrogate errors.</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
