<?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[ image - 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[ image - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 16:30:30 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/image/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build and Deploy an Image Hosting Service on Sevalla ]]>
                </title>
                <description>
                    <![CDATA[ When most people think of image hosting, they imagine uploading photos to a cloud service and getting back a simple link. It feels seamless, but behind that experience sits a powerful set of technologies. At the core is something called object storag... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-and-deploy-an-image-hosting-service-on-sevalla/</link>
                <guid isPermaLink="false">68d691dd9aa70c44b703deb0</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image processing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Fri, 26 Sep 2025 13:15:09 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758890260515/c4b83d17-c783-425c-ab11-50961e44ea58.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When most people think of image hosting, they imagine uploading photos to a cloud service and getting back a simple link.</p>
<p>It feels seamless, but behind that experience sits a powerful set of technologies. At the core is something called object storage, which is a different way of handling files compared to traditional databases or file systems.</p>
<p>In this article, we’ll build a complete image hosting service using <a target="_blank" href="https://nodejs.org/en">Node.js</a> and Express, connect it to object storage, and finally, deploy the whole project to <a target="_blank" href="https://sevalla.com/">Sevalla</a>.</p>
<p>By the end, you will have a working application that lets users upload images and retrieve them through hosted URLs, all running live on the cloud.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-object-storage">What is Object Storage?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-we-will-be-building">What We Will Be Building</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-the-project">How to Set Up the Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-your-object-storage">How to Create Your Object Storage</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-deploy-your-project-on-sevalla">How to Deploy Your Project on Sevalla</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-this-project-matters">Why This Project Matters</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-object-storage"><strong>What is Object Storage?</strong></h2>
<p>To understand why our project is designed the way it is, we need to first understand object storage.</p>
<p>Traditional file storage systems save files in a hierarchy of folders, like your computer’s file explorer. Block storage systems, often used in databases, split data into chunks and manage them for speed and reliability.</p>
<p>Object storage is different. It treats each file, whether an image, video, or document, as a single object. Each object is stored with its metadata and a unique identifier inside a flat structure, usually called a bucket.</p>
<p>This flat architecture makes object storage scalable almost without limit. Instead of worrying about file paths or directories, you simply place an object in a bucket and get back an identifier.</p>
<p><a target="_blank" href="https://aws.amazon.com/s3/">Amazon S3</a> is the industry standard for object storage, offering massive scale, global replication, and advanced features, but it comes with added complexity and often unpredictable costs. Sevalla’s object storage, on the other hand, is designed for developers who want the same durability and scalability without the steep learning curve.</p>
<p>It provides a simpler setup, and is compatible with S3, so interacting with it is same as using a S3 bucket without the additional setup and complexity. While S3 is ideal for enterprises with petabytes of data, Sevalla’s solution is perfect for projects like image hosting, blogs, or mobile apps where ease of use and speed matter most.</p>
<h2 id="heading-what-we-will-be-building"><strong>What We Will Be Building</strong></h2>
<p>We will create a simple yet practical image hosting service. At its core, the service allows a user to send an image through an HTTP request. The server will accept this image, process it, and store it in object storage.</p>
<p>The usefulness of such a project goes far beyond a coding exercise. If you are building a blog, you could use this service to store images for your posts without worrying about file management on your web server.</p>
<p>If you are developing a mobile app that requires profile pictures or image sharing, this backend can serve as your foundation. Even if you simply want to understand how cloud-native applications handle file uploads, this project gives you a clear, hands-on experience.</p>
<p>By the end, you will not just have code running locally. We will deploy the application on Sevalla, meaning your image hosting service will be live, scalable, and accessible to anyone with a link.</p>
<h2 id="heading-how-to-set-up-the-project"><strong>How to Set Up the Project</strong></h2>
<p>Let us start by setting up a Node.js project. You can <a target="_blank" href="https://github.com/manishmshiva/image-host">clone this repository</a> if you don’t want to setup the project from scratch.</p>
<p>Create a new project directory, initialize it with npm, and install the required dependencies.</p>
<pre><code class="lang-plaintext">npm init -y
npm i express multer dotenv @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
</code></pre>
<p>We will use <a target="_blank" href="https://expressjs.com/">Express</a> for our web server, <a target="_blank" href="https://www.npmjs.com/package/multer">Multer</a> for handling file uploads, and the <a target="_blank" href="https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/welcome.html">AWS SDK</a> to connect to object storage. Multer acts as middleware, giving us easy access to uploaded files. The AWS SDK gives us programmatic access to object storage, allowing us to upload files and generate links.</p>
<p>Let’s write a quick <code>index.html</code> and put it inside the <code>public/</code> directory to serve as the UI for file upload.</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!doctype <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span> /&gt;</span> <span class="hljs-comment">&lt;!-- Set character encoding --&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-comment">&lt;!-- Mobile-friendly --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Pic Host<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Simple CSS styling for layout and form --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
    <span class="hljs-selector-pseudo">:root</span> { <span class="hljs-attribute">color-scheme</span>: light dark; } <span class="hljs-comment">/* Support dark/light themes */</span>
    <span class="hljs-selector-tag">body</span> { 
      <span class="hljs-attribute">font-family</span>: system-ui, sans-serif; 
      <span class="hljs-attribute">max-width</span>: <span class="hljs-number">560px</span>; 
      <span class="hljs-attribute">margin</span>: <span class="hljs-number">4rem</span> auto; 
      <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span> <span class="hljs-number">1rem</span>; 
    }
    <span class="hljs-selector-tag">h1</span> { <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.25rem</span>; <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1rem</span>; }
    <span class="hljs-selector-tag">form</span>, <span class="hljs-selector-class">.card</span> { 
      <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#9993</span>; 
      <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>; 
      <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">12px</span>; 
    }
    <span class="hljs-selector-tag">input</span><span class="hljs-selector-attr">[type=<span class="hljs-string">"file"</span>]</span> { <span class="hljs-attribute">margin</span>: .<span class="hljs-number">5rem</span> <span class="hljs-number">0</span> <span class="hljs-number">1rem</span>; }
    <span class="hljs-selector-tag">button</span> { 
      <span class="hljs-attribute">padding</span>: .<span class="hljs-number">6rem</span> <span class="hljs-number">1rem</span>; 
      <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">10px</span>; 
      <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#9995</span>; 
      <span class="hljs-attribute">background</span>: <span class="hljs-number">#0000FF</span>; 
      <span class="hljs-attribute">cursor</span>: pointer; 
    }
    <span class="hljs-selector-id">#result</span> { <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">1rem</span>; <span class="hljs-attribute">display</span>: none; }
    <span class="hljs-selector-id">#result</span> <span class="hljs-selector-tag">a</span> { <span class="hljs-attribute">word-break</span>: break-all; } <span class="hljs-comment">/* Break long URLs nicely */</span>
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- Page heading --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Simple Image Host<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Upload form --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"uploadForm"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"file"</span>&gt;</span>Choose image<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"file"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"file"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"file"</span> <span class="hljs-attr">accept</span>=<span class="hljs-string">"image/*"</span> <span class="hljs-attr">required</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">br</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;</span>Upload<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Status text (uploading, success, error) --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"status"</span> <span class="hljs-attr">aria-live</span>=<span class="hljs-string">"polite"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"margin-top:.75rem;"</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">form</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Result card: hidden until an image is uploaded --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"result"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</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">strong</span>&gt;</span>Share this page:<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> 
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"pageUrl"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"noopener"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- Client-side JavaScript --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">const</span> form = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'uploadForm'</span>);   <span class="hljs-comment">// Form element</span>
    <span class="hljs-keyword">const</span> statusEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'status'</span>);   <span class="hljs-comment">// Upload status</span>
    <span class="hljs-keyword">const</span> result = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'result'</span>);     <span class="hljs-comment">// Result box</span>
    <span class="hljs-keyword">const</span> pageUrlEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'pageUrl'</span>); <span class="hljs-comment">// Share link</span>
    <span class="hljs-keyword">const</span> directUrlEl = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'directUrl'</span>); <span class="hljs-comment">// (unused here)</span>

    <span class="hljs-comment">// Event listener for form submission</span>
    form.addEventListener(<span class="hljs-string">'submit'</span>, <span class="hljs-keyword">async</span> (e) =&gt; {
      e.preventDefault(); <span class="hljs-comment">// Prevent full-page reload</span>
      statusEl.textContent = <span class="hljs-string">'Uploading...'</span>; 
      result.style.display = <span class="hljs-string">'none'</span>;

      <span class="hljs-keyword">const</span> fd = <span class="hljs-keyword">new</span> FormData(); <span class="hljs-comment">// FormData object for sending file</span>
      <span class="hljs-keyword">const</span> file = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'file'</span>).files[<span class="hljs-number">0</span>];
      <span class="hljs-keyword">if</span> (!file) {
        statusEl.textContent = <span class="hljs-string">'Pick a file first.'</span>;
        <span class="hljs-keyword">return</span>;
      }
      fd.append(<span class="hljs-string">'file'</span>, file); <span class="hljs-comment">// Attach file to request</span>

      <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Send file to backend /upload route</span>
        <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'/upload'</span>, { <span class="hljs-attr">method</span>: <span class="hljs-string">'POST'</span>, <span class="hljs-attr">body</span>: fd });
        <span class="hljs-keyword">if</span> (!res.ok) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">'Upload failed'</span>);
        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> res.json();

        <span class="hljs-comment">// Show returned page URL</span>
        pageUrlEl.textContent = data.pageUrl;
        pageUrlEl.href = data.pageUrl;

        <span class="hljs-comment">// Display result card and reset form</span>
        result.style.display = <span class="hljs-string">'block'</span>;
        statusEl.textContent = <span class="hljs-string">'Done!'</span>;
        form.reset();
      } <span class="hljs-keyword">catch</span> (err) {
        <span class="hljs-comment">// Handle error</span>
        statusEl.textContent = <span class="hljs-string">'Error: '</span> + err.message;
      }
    });
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>When a user visits the page, they’ll see a simple upload form with a file picker. They can select an image from their computer and click Upload. Then JavaScript intercepts the form submission using <code>addEventListener('submit')</code>, prevents the browser from doing a full page refresh, and instead, packages the selected file into a <code>FormData</code> object.</p>
<p>That file is then sent to the server with a <code>fetch</code> call to the <code>/upload</code> route. If the server responds successfully, the JSON returned contains a <code>pageUrl</code>. This URL is displayed inside the result card, which was initially hidden. The user can now copy this link and share it with others.</p>
<p>If something goes wrong, like no file being selected, the server erroring out, or the upload failing, the script updates the status message to inform the user.</p>
<p>Here’s how it looks to the user.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757306506845/aed05c76-954e-4bae-a995-8efc2da89f10.jpeg" alt="Index.html" class="image--center mx-auto" width="1100" height="477" loading="lazy"></p>
<p>Now let’s create the backend using <code>server.js</code> file.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">"path"</span>; <span class="hljs-comment">// For working with file paths</span>
<span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">"express"</span>; <span class="hljs-comment">// Web framework to handle HTTP routes</span>
<span class="hljs-keyword">import</span> multer <span class="hljs-keyword">from</span> <span class="hljs-string">"multer"</span>; <span class="hljs-comment">// Middleware for handling file uploads</span>
<span class="hljs-keyword">import</span> crypto <span class="hljs-keyword">from</span> <span class="hljs-string">"crypto"</span>; <span class="hljs-comment">// Used to generate random unique IDs</span>
<span class="hljs-keyword">import</span> dotenv <span class="hljs-keyword">from</span> <span class="hljs-string">"dotenv"</span>; <span class="hljs-comment">// Loads environment variables from .env file</span>
<span class="hljs-keyword">import</span> { fileURLToPath } <span class="hljs-keyword">from</span> <span class="hljs-string">"url"</span>; <span class="hljs-comment">// For handling ES module file paths</span>
<span class="hljs-keyword">import</span> {
  S3Client,
  PutObjectCommand,
  HeadObjectCommand,
  GetObjectCommand,
} <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/client-s3"</span>; <span class="hljs-comment">// AWS SDK commands for S3 operations</span>
<span class="hljs-keyword">import</span> { getSignedUrl } <span class="hljs-keyword">from</span> <span class="hljs-string">"@aws-sdk/s3-request-presigner"</span>; <span class="hljs-comment">// To generate temporary signed URLs</span>

dotenv.config(); <span class="hljs-comment">// Load environment variables</span>

<span class="hljs-comment">// Setup paths for __dirname and __filename in ES modules</span>
<span class="hljs-keyword">const</span> __filename = fileURLToPath(<span class="hljs-keyword">import</span>.meta.url);
<span class="hljs-keyword">const</span> __dirname = path.dirname(__filename);

<span class="hljs-comment">// Bucket name from environment</span>
<span class="hljs-keyword">const</span> S3_BUCKET = process.env.S3_BUCKET;

<span class="hljs-comment">// Create an S3 client (works with Sevalla-compatible storage as well)</span>
<span class="hljs-keyword">const</span> s3 = <span class="hljs-keyword">new</span> S3Client({
  <span class="hljs-attr">region</span>: <span class="hljs-string">"auto"</span>, <span class="hljs-comment">// Auto-region for Sevalla</span>
  <span class="hljs-attr">endpoint</span>: process.env.ENDPOINT, <span class="hljs-comment">// Custom endpoint for object storage</span>
  <span class="hljs-attr">credentials</span>: {
    <span class="hljs-attr">accessKeyId</span>: process.env.AWS_ACCESS_KEY_ID, <span class="hljs-comment">// From .env</span>
    <span class="hljs-attr">secretAccessKey</span>: process.env.AWS_SECRET_ACCESS_KEY, <span class="hljs-comment">// From .env</span>
  },
});

<span class="hljs-comment">// Initialize Express app</span>
<span class="hljs-keyword">const</span> app = express();

<span class="hljs-comment">// Serve static files (like index.html, CSS, JS) from "public" folder</span>
app.use(express.static(path.join(__dirname, <span class="hljs-string">"public"</span>)));

<span class="hljs-comment">// Multer setup: store uploaded files in memory (not on disk)</span>
<span class="hljs-comment">// Limit file size to 10MB</span>
<span class="hljs-keyword">const</span> upload = multer({
  <span class="hljs-attr">storage</span>: multer.memoryStorage(),
  <span class="hljs-attr">limits</span>: { <span class="hljs-attr">fileSize</span>: <span class="hljs-number">10</span> * <span class="hljs-number">1024</span> * <span class="hljs-number">1024</span> },
});

<span class="hljs-comment">// ---------- ROUTE 1: GET / ----------</span>
<span class="hljs-comment">// Serves the main HTML file (upload form)</span>
app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.sendFile(path.join(__dirname, <span class="hljs-string">"public"</span>, <span class="hljs-string">"index.html"</span>));
});

<span class="hljs-comment">// ---------- ROUTE 2: POST /upload ----------</span>
<span class="hljs-comment">// Handles image uploads and stores them in object storage</span>
app.post(<span class="hljs-string">"/upload"</span>, upload.single(<span class="hljs-string">"file"</span>), <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Check if file exists</span>
    <span class="hljs-keyword">if</span> (!req.file) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"file is required"</span> });

    <span class="hljs-comment">// Generate a random ID for the file</span>
    <span class="hljs-keyword">const</span> id = crypto.randomUUID().replace(<span class="hljs-regexp">/-/g</span>, <span class="hljs-string">""</span>);
    <span class="hljs-keyword">const</span> key = id;

    <span class="hljs-comment">// Create a PutObjectCommand to upload file to S3/Sevalla</span>
    <span class="hljs-keyword">const</span> put = <span class="hljs-keyword">new</span> PutObjectCommand({
      <span class="hljs-attr">Bucket</span>: S3_BUCKET,
      <span class="hljs-attr">Key</span>: key,
      <span class="hljs-attr">Body</span>: req.file.buffer,
      <span class="hljs-attr">ContentType</span>: req.file.mimetype,
      <span class="hljs-attr">Metadata</span>: {
        <span class="hljs-attr">originalname</span>: req.file.originalname || <span class="hljs-string">""</span>,
      },
    });

    <span class="hljs-comment">// Upload the file</span>
    <span class="hljs-keyword">await</span> s3.send(put);

    <span class="hljs-comment">// Build a page URL for retrieving the image later</span>
    <span class="hljs-keyword">const</span> baseUrl = <span class="hljs-string">`<span class="hljs-subst">${req.protocol}</span>://<span class="hljs-subst">${req.get(<span class="hljs-string">"host"</span>)}</span>`</span>;
    <span class="hljs-keyword">const</span> pageUrl = <span class="hljs-string">`<span class="hljs-subst">${baseUrl}</span>/i/<span class="hljs-subst">${id}</span>`</span>;

    <span class="hljs-comment">// Respond with the page URL</span>
    res.json({ id, pageUrl });
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err);
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"upload_failed"</span> });
  }
});

<span class="hljs-comment">// ---------- ROUTE 3: GET /i/:id ----------</span>
<span class="hljs-comment">// Redirects to a signed URL for secure access to the uploaded file</span>
app.get(<span class="hljs-string">"/i/:id"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> { id } = req.params;
  <span class="hljs-keyword">const</span> key = id;

  <span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// Ensure the object exists in storage</span>
    <span class="hljs-keyword">await</span> s3.send(<span class="hljs-keyword">new</span> HeadObjectCommand({ <span class="hljs-attr">Bucket</span>: S3_BUCKET, <span class="hljs-attr">Key</span>: key }));

    <span class="hljs-comment">// Create a signed URL valid for 1 hour</span>
    <span class="hljs-keyword">const</span> command = <span class="hljs-keyword">new</span> GetObjectCommand({ <span class="hljs-attr">Bucket</span>: S3_BUCKET, <span class="hljs-attr">Key</span>: key });
    <span class="hljs-keyword">const</span> signedUrl = <span class="hljs-keyword">await</span> getSignedUrl(s3, command, { <span class="hljs-attr">expiresIn</span>: <span class="hljs-number">3600</span> });

    <span class="hljs-comment">// Redirect user to the signed URL</span>
    <span class="hljs-keyword">return</span> res.redirect(<span class="hljs-number">302</span>, signedUrl);
  } <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.error(err);
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).send(<span class="hljs-string">"Not found"</span>);
  }
});

<span class="hljs-comment">// ---------- Boot the Server ----------</span>
app.listen(process.env.PORT || <span class="hljs-number">3000</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Image host server listening for requests...`</span>);
});
</code></pre>
<h3 id="heading-route-1-get">Route 1: <code>GET /</code></h3>
<p>This is the entry point of the app. When you open the browser and go to the root URL, it serves the <code>index.html</code> file from the <code>public</code> folder. That file contains the upload form where the user can select an image and submit it.</p>
<h3 id="heading-route-2-post-upload">Route 2: <code>POST /upload</code></h3>
<p>This is where the magic happens. When a user selects an image and clicks “Upload,” the file is sent to this endpoint. Multer handles the file upload in memory, and then the file is pushed to object storage using the <code>PutObjectCommand</code>. A random unique ID is generated as the key for the file. Once uploaded, the server responds with a <code>pageUrl</code> that can be used to view the uploaded image later.</p>
<h3 id="heading-route-3-get-iid">Route 3: <code>GET /i/:id</code></h3>
<p>This route retrieves an uploaded image. Instead of serving the file directly, it generates a signed URL valid for one hour using <code>getSignedUrl</code>. This signed URL gives temporary access to the file stored in object storage. The server then redirects the user to that signed URL. If the file doesn’t exist, it returns a 404 error.</p>
<p>Before you run this code, we need access to the object storage and add the value in an environment file. The code you see <code>process.env</code> fetches these values and helps us authenticate with the object storage to read and write files.</p>
<h2 id="heading-how-to-create-your-object-storage"><strong>How to Create Your Object Storage</strong></h2>
<p><a target="_blank" href="https://app.sevalla.com/login">Login</a> to Sevalla and click “Object Storage”. Click “Create Object Storage” and give it a name.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757306560384/3e88b143-2fa9-465d-b3d6-e0e54c90a6a3.jpeg" alt="Object Storage Creation" class="image--center mx-auto" width="1100" height="545" loading="lazy"></p>
<p>Once created, click “Settings” and you will see the access key and secret key. We need these four values</p>
<ul>
<li><p>Bucket name</p>
</li>
<li><p>Endpoint URL</p>
</li>
<li><p>Access Key</p>
</li>
<li><p>Secret Key</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757306618051/90970694-3d7c-486f-b32a-54c83ca88c7f.jpeg" alt="Object Storage Access Keys" class="image--center mx-auto" width="1100" height="354" loading="lazy"></p>
<p>Copy them into a file named <code>.env</code> within your project.</p>
<pre><code class="lang-plaintext">AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID_HERE
AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY_HERE
S3_BUCKET=YOUR_BUCKET_NAME_HERE
ENDPOINT=YOUR_ENDPOINT_URL_HERE
</code></pre>
<p>Additionally, enable public access in the settings so that you can push files from your local environment.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757306660300/7abe369e-f820-4770-82d7-27da03c9b7a9.jpeg" alt="public access enabled" class="image--center mx-auto" width="1100" height="176" loading="lazy"></p>
<h3 id="heading-testing-the-application-locally"><strong>Testing the Application Locally</strong></h3>
<p>Let’s make sure our code works locally.</p>
<pre><code class="lang-bash">node server.js
</code></pre>
<p>Go to <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a> and try uploading a file. It should give you the URL to view the file after a successful upload.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757306699833/b95b69ed-17f6-4fe9-b0a8-22e15876655d.jpeg" alt="File upload success" class="image--center mx-auto" width="1100" height="610" loading="lazy"></p>
<p>You can visit the URL to see your uploaded file. You can also double check if it has been uploaded using the Object Storage UI.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757306733665/35944857-71bb-4d1a-9e11-85c35c875465.jpeg" alt="Object Storage UI" class="image--center mx-auto" width="1100" height="308" loading="lazy"></p>
<p>Great. We have built a simple image hosting and sharing service. Now let’s get this into the cloud.</p>
<h2 id="heading-how-to-deploy-your-project-on-sevalla"><strong>How to Deploy Your Project on Sevalla</strong></h2>
<p>First, push your project to GitHub or <a target="_blank" href="https://github.com/manishmshiva/image-host">fork my repository</a>. Then log in to your Sevalla dashboard and create a new application.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757306768439/3be4f9ac-abd4-4b98-95e3-22b97a3eea1a.jpeg" alt="Create application" class="image--center mx-auto" width="1100" height="767" loading="lazy"></p>
<p>Connect your GitHub account, choose the repository that contains your image hosting service, and select the branch you want to deploy. Sevalla will automatically detect that it is a Node.js project and install dependencies. It will also run the application on the specified port.</p>
<p>To configure AWS credentials and bucket information, go to the environment variables section in your app and add your <code>AWS_ACCESS_KEY_ID</code>, <code>AWS_SECRET_ACCESS_KEY</code>, <code>AWS_REGION</code>, and <code>S3_BUCKET_NAME</code>. These values will be injected into your application at runtime, ensuring that sensitive data is not hardcoded into your source code.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757306811113/b5e1782d-2bce-4b9e-a654-a131e58a44cd.jpeg" alt="Adding environment variables" class="image--center mx-auto" width="1100" height="500" loading="lazy"></p>
<p>Once environment variables are added, go to “Overview” and click “Deploy”.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757306855343/fbcfcd74-d74e-43ad-9b99-7f02421cf5df.jpeg" alt="fbcfcd74-d74e-43ad-9b99-7f02421cf5df" class="image--center mx-auto" width="1100" height="622" loading="lazy"></p>
<p>Wait for a few minutes. Once the deployment is complete, Sevalla will give you a live URL. Click “Visit APP” to go to your application’s page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757306886378/97705a1f-c625-4282-9ef0-042c8c01b431.jpeg" alt="Live url" class="image--center mx-auto" width="1100" height="332" loading="lazy"></p>
<p>Congratulations! Your app is now live. You can share the URL with others or even add a custom domain to your app to have your own image hosting solution.</p>
<h2 id="heading-why-this-project-matters"><strong>Why This Project Matters</strong></h2>
<p>This project is more than just a coding exercise. It teaches you how modern applications manage files at scale, introduces you to object storage, and shows how to integrate cloud services into your own projects.</p>
<p>With Sevalla, you also learned how to deploy production-ready applications, giving you the full cycle from local prototype to live cloud service.</p>
<p>For developers building blogs, mobile apps, or even internal tools, the ability to host images reliably and at scale is invaluable. With object storage and a simple Node.js service, you can avoid reinventing the wheel and rely on proven cloud infrastructure.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>We began by exploring object storage and why it is ideal for handling files like images. We then built a Node.js application that accepts uploads, stores them in Sevalla’s Object Storage, and returns accessible URLs. Finally, we deployed the application on Sevalla, turning a local project into a live image hosting service. Along the way, you gained not only working code but also a deeper understanding of how to build cloud-native services.</p>
<p>By completing this project, you now have a working image hosting service you can extend and adapt. You could add features like authentication, image resizing, or even a better front-end interface with drag-and-drop UI. Most importantly, you have experienced how development and deployment fit together in modern software.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ SVG Tutorial – How to Code Images with 12 Examples ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever needed an icon for your website, but you couldn't quite find the right one? Or perhaps you wanted to have a simple diagram, but didn't want to learn a whole new library just for that? Well, good news – you can do all that and more witho... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/svg-tutorial-learn-to-code-images/</link>
                <guid isPermaLink="false">66c4c81d4173ed342943d0c4</guid>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SVG ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Hunor Márton Borbély ]]>
                </dc:creator>
                <pubDate>Mon, 04 Dec 2023 12:29:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/10/Learn-SVG.001.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever needed an icon for your website, but you couldn't quite find the right one? Or perhaps you wanted to have a simple diagram, but didn't want to learn a whole new library just for that?</p>
<p>Well, good news – you can do all that and more without ever leaving your favorite code editor or using any third party tools or libraries.</p>
<p>Since HTML5, we can include the code of an SVG image inside an HTML document. We don’t even need to use the image tag that refers to a separate file. We can inline the code of an image right inside the HTML. We can do this because SVGs have a very similar syntax to HTML.</p>
<p>This opens up a lot of cool options. Suddenly we can access parts of an image from JavaScript or set the style from CSS. We can animate parts of an image from JavaScript or make it interactive. Or we can turn things around and generate graphics from code.</p>
<p>For more complicated images, you will still use a designer tool. But the next time you need a simple icon, a diagram, or animation, maybe you can code it yourself.</p>
<p>So how do SVGs look like under the surface? In this tutorial, we go through the source code of a few SVGs to cover the foundations.</p>
<p>The following examples are from <a target="_blank" href="https://svg-tutorial.com">svg-tutorial.com</a>. You can also <a target="_blank" href="https://youtu.be/kBT90nwUb_o">watch this article as a video</a> with even more fun examples.</p>
<h2 id="heading-the-svg-tag"><strong>The SVG tag</strong></h2>
<p>First, we have to talk about the <code>svg</code> tag itself. This tag contains the image elements and defines the frame of our image. It sets the inner size and the outer size of the image.</p>
<p>The <code>width</code> and <code>height</code> property define how much space the image takes up in the browser. There’s often a <code>viewBox</code> property as well. This defines a coordinate system for the elements inside the image. These two can be confusing because they both define a size.</p>
<p>You can think of the <code>width</code> and <code>height</code> of an SVG as an external size and the <code>viewBox</code> as an internal size.</p>
<p>The size defined by <code>width</code> and <code>height</code> is how the rest of HTML thinks of the image and how big it appears in the browser. The size defined by <code>viewBox</code> is how the image elements think of the image when they position themselves inside of it.</p>
<p>In the next example we have three SVGs that have the very same content. A <code>circle</code> element with the same center coordinate and same radius. They appear quite different, though.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Learn-SVG.001-1.jpeg" alt="Learn-SVG.001-1" width="600" height="400" loading="lazy">
<em>The very same circle can appear different based on the size of the image and the <code>viewBox</code> property</em></p>
<p>At the example in the middle, the size defined by <code>width</code> and <code>height</code> matches the one defined by the <code>viewbox</code>. In the first example we see what happens if the <code>width</code> and <code>height</code> are smaller. The image simply shrinks down as all the coordinates and sizes defined within the image still align to the <code>viewbox</code>.</p>
<p>In the last example we see what happens if the <code>viewbox</code> is focusing on only part of the image. Things appear bigger in this case, but the actual size of the image is still defined by the <code>width</code> and <code>height</code> property.</p>
<p>The <code>viewBox</code> also defines the center of the coordinate system in which the image items place themselves.</p>
<p>The first two numbers define which coordinate should be at the top left corner of the image. Coordinates grow to the right and downwards. In this article, we will center the coordinate systems. The 0,0 coordinate will always be in the middle of the image.</p>
<p>One note before we start: while we can inline SVG images in an HTML file, that doesn’t mean we can freely combine any SVG tag with any HTML tag.</p>
<p>The SVG tag represents the frame of the image and every SVG element has to come within an SVG tag. The same is true in the opposite direction. HTML tags can’t be within an SVG tag, so we can’t have a div or a header tag inside an SVG. But don’t worry, there are similar tags available.</p>
<h2 id="heading-how-to-make-a-christmas-ornament-with-svg"><strong>How to Make a Christmas Ornament with SVG</strong></h2>
<p>Let’s start with a simple Christmas tree ornament. Here we'll only use simple shapes. A rectangle, and two circles.</p>
<p>We'll position and style these elements with attributes. For the circle, we define the center position and for the rectangle, we define the top left corner. These positions are always related to the coordinate system defined by the viewBox.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Learn-SVG.002-1.jpeg" alt="Learn-SVG.002-1" width="600" height="400" loading="lazy">
<em>Christmas Ornament made out of circles and a rectangle. On the right you can see the coordinates we use in this example.</em></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200”&gt;
    &lt;circle cx="</span><span class="hljs-attr">0</span>" <span class="hljs-attr">cy</span>=<span class="hljs-string">"20"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"70"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#D1495B"</span> /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">circle</span>
      <span class="hljs-attr">cx</span>=<span class="hljs-string">"0"</span>
      <span class="hljs-attr">cy</span>=<span class="hljs-string">"-75"</span>
      <span class="hljs-attr">r</span>=<span class="hljs-string">"12"</span>
      <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>
      <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#F79257"</span>
      <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"2"</span>
    /&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">rect</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-17.5"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-65"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"35"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"20"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#F79257"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Remember, we moved the center of the coordinate system to the middle of the image and the X-axis grows to the right and the Y-axis grows towards the bottom.</p>
<p>We also have presentational attributes that style our shapes. Unlike in HTML, we do not use <code>background-color</code> to set a color for a shape but we use the <code>fill</code> attribute.</p>
<p>And to set a border for a shape we use <code>stroke</code> and <code>stroke-width</code>. Note how we use the circle element both to draw a ring and a ball with different attributes.</p>
<h2 id="heading-how-to-build-a-christmas-tree-with-svg"><strong>How to Build a Christmas Tree with SVG</strong></h2>
<p>Let’s move on to a Christmas tree. We can’t always use basic shapes to assemble our image. A polygon is the simplest way to draw a freeform shape. Here we set a list of points that are connected with straight lines.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Learn-SVG.003.jpeg" alt="Learn-SVG.003" width="600" height="400" loading="lazy">
<em>Christmas Tree made out of polygons and a rectangle</em></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 80,120 -80,120"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#234236"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,-40 60,60 -60,60"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#0C5C4C"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,-80 40,0 -40,0"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#38755B"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">rect</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-20"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"120"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"40"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"brown"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>You might be wondering how we know before starting to code where our coordinates should be.</p>
<p>To be honest, this requires a bit of imagination. You can start with pen and paper and draw a draft first to get an estimate. Or you can just make a guess then adjust your values until it looks good.</p>
<h2 id="heading-how-to-make-a-gingerbread-figure-with-svg"><strong>How to Make a Gingerbread Figure with SVG</strong></h2>
<p>Let’s move on with a gingerbread figure. Since our SVG is living inside an HTML file now, we can assign CSS classes to each tag and move some attributes to CSS.</p>
<p>We can only move the presentation attributes, though. Position attributes and attributes that define the shape still have to stay in the HTML. But we can move colors, stroke, and font attributes to CSS.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Learn-SVG.004.jpeg" alt="Learn-SVG.004" width="600" height="400" loading="lazy">
<em>Gingerbread figure example. On the right you can see how would it look if the <code>stroke-width</code> were one</em></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"gingerbread"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"body"</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"-50"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"30"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"eye"</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"-12"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"-55"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"3"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"eye"</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"12"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"-55"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"3"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">rect</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"mouth"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-10"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-40"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"20"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"5"</span> <span class="hljs-attr">rx</span>=<span class="hljs-string">"2"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">line</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"limb"</span> <span class="hljs-attr">x1</span>=<span class="hljs-string">"-40"</span> <span class="hljs-attr">y1</span>=<span class="hljs-string">"-10"</span> <span class="hljs-attr">x2</span>=<span class="hljs-string">"40"</span> <span class="hljs-attr">y2</span>=<span class="hljs-string">"-10"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">line</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"limb"</span> <span class="hljs-attr">x1</span>=<span class="hljs-string">"-25"</span> <span class="hljs-attr">y1</span>=<span class="hljs-string">"50"</span> <span class="hljs-attr">x2</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">y2</span>=<span class="hljs-string">"-15"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">line</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"limb"</span> <span class="hljs-attr">x1</span>=<span class="hljs-string">"25"</span> <span class="hljs-attr">y1</span>=<span class="hljs-string">"50"</span> <span class="hljs-attr">x2</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">y2</span>=<span class="hljs-string">"-15"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"-10"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"5"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"5"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.gingerbread</span> <span class="hljs-selector-class">.body</span> {
  <span class="hljs-attribute">fill</span>: <span class="hljs-number">#cd803d</span>;
}

<span class="hljs-selector-class">.gingerbread</span> <span class="hljs-selector-class">.eye</span> {
  <span class="hljs-attribute">fill</span>: white;
}

<span class="hljs-selector-class">.gingerbread</span> <span class="hljs-selector-class">.mouth</span> {
  <span class="hljs-attribute">fill</span>: none;
  <span class="hljs-attribute">stroke</span>: white;
  <span class="hljs-attribute">stroke-width</span>: <span class="hljs-number">2px</span>;
}

<span class="hljs-selector-class">.gingerbread</span> <span class="hljs-selector-class">.limb</span> {
  <span class="hljs-attribute">stroke</span>: <span class="hljs-number">#cd803d</span>;
  <span class="hljs-attribute">stroke-width</span>: <span class="hljs-number">35px</span>;
  <span class="hljs-attribute">stroke-linecap</span>: round;
}
</code></pre>
<p>We already saw the fill and some of the stroke properties, but here’s another one – the <code>stroke-linecap</code>. This can make our line cap round.</p>
<p>Note that the legs and the arms are simple lines here. If we remove the line cap and set a smaller <code>stroke-width</code>, then we can see that these are simple lines. But by setting a thick stroke width and a round line cap we can shape legs and arms for our figure.</p>
<p>Also note the <code>rx</code> property at the rectangle defining the mouth. This will make the edges round. You can think of it as <code>border-radius</code> if you like.</p>
<h2 id="heading-how-to-make-a-star-with-svg"><strong>How to Make a Star with SVG</strong></h2>
<p>Let’s move on to a star. A star is a simple shape, so we can define it as a bunch of polygons and set each point individually. But then we would need to know each coordinate.</p>
<p>Instead of that, we can just define one wing as a group, then repeat it five times with a rotation to get the star's shape. We use the <code>transform</code> attribute to set a rotation.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Learn-SVG.005.jpeg" alt="Learn-SVG.005" width="600" height="400" loading="lazy">
<em>Star shape made out of transformed polygons. On the right we can see the coordianates of one arm of the star</em></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200"</span>&gt;</span>      
  <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"translate(0 5)"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">g</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 36,-50 0,-100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#EDD8B7"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 -36,-50 0,-100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#E5C39C"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"rotate(72)"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 36,-50 0,-100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#EDD8B7"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 -36,-50 0,-100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#E5C39C"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"rotate(-72)"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 36,-50 0,-100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#EDD8B7"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 -36,-50 0,-100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#E5C39C"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"rotate(144)"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 36,-50 0,-100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#EDD8B7"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 -36,-50 0,-100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#E5C39C"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"rotate(-144)"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 36,-50 0,-100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#EDD8B7"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"0,0 -36,-50 0,-100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#E5C39C"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<p>In this example, each wing consists of two polygons. They need to be rotated the same way, so we can group them with a <code>g</code> tag and <code>rotate</code> them together.</p>
<p>You can think of the <code>g</code> tag as the <code>div</code> tag in HTML. On its own, it does not represent anything. But it can contain other elements and attributes defined on the group tag apply to its children.</p>
<p>Groups can be embedded. With the outer group we <code>translate</code> the whole star downwards by 5 units.</p>
<h2 id="heading-how-to-make-a-snowflake-with-svg"><strong>How to Make a Snowflake with SVG</strong></h2>
<p>Grouping elements is a nice trick, but we had to repeat the same code for each wing five times.</p>
<p>Instead of repeating the same code over and over again, we can also create a definition for a shape and reuse it by <code>id</code>. Here we define a branch of a snowflake then use it six times with different rotations.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Learn-SVG.006.jpeg" alt="Learn-SVG.006" width="600" height="400" loading="lazy">
<em>Snowflake made out of reused image elements. On the right we can see the coordainates use for an arm</em></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">defs</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
      <span class="hljs-attr">id</span>=<span class="hljs-string">"branch"</span>
      <span class="hljs-attr">d</span>=<span class="hljs-string">"
        M 0 0 L 0 -90
        M 0 -20 L 20 -34
        M 0 -20 L -20 -34
        M 0 -40 L 20 -54
        M 0 -40 L -20 -54
        M 0 -60 L 20 -74
        M 0 -60 L -20 -74"</span>
      <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#E5C39C"</span>
      <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"5"</span>
    /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">defs</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#branch"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#branch"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"rotate(60)"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#branch"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"rotate(120)"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#branch"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"rotate(180)"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#branch"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"rotate(240)"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#branch"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"rotate(300)"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<p>The branch is defined as a <code>path</code>. The <code>path</code> is the most powerful SVG tag. We can define pretty much anything with paths, and if you open any SVG file, you will see mostly paths.</p>
<p>The shape of the path is defined by the <code>d</code> attribute. Here we define several drawing commands. A command always starts with a letter defining the command type and ends with a coordinate.</p>
<p>Here we only have the two most simple commands, move to (<code>M</code>) and line to (<code>L</code>). The <code>move to</code> command moves the cursor to a point without drawing a line and the <code>line to</code> command draws a straight line from the previous point.</p>
<p>A command always continues the previous command, so when we draw a line we only define the endpoint. The starting point will be the previous command’s endpoint.</p>
<p>This path is a bit unusual because there are several move to commands in it to draw the main branch and each side branch with the same path.</p>
<h2 id="heading-how-to-draw-a-forest-with-svg">How to Draw a Forest with SVG</h2>
<p>Rotation is not the only way we can generate images from simple shapes. In this example, we define a tree shape and then place it at various positions in different sizes to draw a forest.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Screenshot-2023-11-30-at-21.21.23.png" alt="Image" width="600" height="400" loading="lazy">
<em>Forest made out of reused image elements</em></p>
<p>First, we create a background out of a rectangle and a circle. Then we define a tree shape from a simple polygon and a line.</p>
<p>Then we can reuse it in a similar way as we did in the snowflake example. We move it to the <code>defs</code> section, wrap it into a group element, set an ID for it, and then reuse it with the <code>use</code> element.</p>
<p>Here we also position the reused elements by setting an <code>x</code> and <code>y</code> coordinate and to add some perspective to the image we use the <code>scale</code> transformation.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">defs</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tree"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"-10,0 10,0 0 -50"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#38755b"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">line</span> <span class="hljs-attr">x1</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">y1</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">x2</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">y2</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#778074"</span> <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"2"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">defs</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">rect</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-100"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-100"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#F1DBC3"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"380"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"350"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#F8F4E8"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#tree"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-30"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"25"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"scale(2)"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#tree"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-20"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"40"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"scale(1.2)"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#tree"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"40"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"40"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#tree"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"50"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"scale(1.5)"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<h2 id="heading-how-to-make-a-curvy-tree-with-svg"><strong>How to Make a Curvy Tree with SVG</strong></h2>
<p>The path element becomes really powerful when we start using curves. One of them is the quadratic Bézier curve that not only defines an endpoint for a segment but also has a control point. The control point is an invisible coordinate towards which the line is bending, but not touching it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Learn-SVG.007.jpeg" alt="Learn-SVG.007" width="600" height="400" loading="lazy">
<em>Christmas Tree made using Quadratic Bézier curves</em></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"400"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -200 200 400"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
    <span class="hljs-attr">d</span>=<span class="hljs-string">"
      M 0 -80
      Q 5 -75 0 -70
      Q -10 -65 0 -60
      Q 15 -55 0 -50
      Q -20 -45 0 -40
      Q 25 -35 0 -30
      Q -30 -25 0 -20
      Q 35 -15 0 -10
      Q -40 -5 0 0
      Q 45 5 0 10
      Q -50 15 0 20
      Q 55 25 0 30
      Q -60 35 0 40
      Q 65 45 0 50
      Q -70 55 0 60
      Q 75 65 0 70
      Q -80 75 0 80
      Q 85 85 0 90
      Q -90 95 0 100
      Q 95 105 0 110
      Q -100 115 0 120
      L 0 140
      L 20 140
      L -20 140"</span>
    <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>
    <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#0C5C4C"</span>
    <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"5"</span>
  /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<p>Here we have a series of quadratic Béziers curves (<code>Q</code>) where the control points get further and further away from the center of the tree as the path goes down.</p>
<h2 id="heading-how-to-make-a-bell-with-svg"><strong>How to Make a Bell with SVG</strong></h2>
<p>While the quadratic bezier curve (<code>Q</code>) is great when we want to bend a line, often it’s not flexible enough.</p>
<p>With a cubic Bezier (<code>C</code>), we not only one have one control point but two. The first control point sets the initial direction of the curve and the second one defines from which direction the curve should arrive to its endpoint.</p>
<p>If these directions match the directions of the line before and the line after the curve, then we have a smooth transition between the path segments.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Learn-SVG.008.jpeg" alt="Learn-SVG.008" width="600" height="400" loading="lazy">
<em>With Cubic Bézier curves we can set two control points</em></p>
<p>The next example uses both quadratic and cubic Béziers to form a bell. Here the bottom of this bell is defined with straight lines. Then a quadratic Béziers starts the bell cloak. Next a cubic Bezier smoothly continues the quadratic bezier as it forms the top of the bell. Then we reach the bottom part with another quadratic bezier.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/12/Learn-SVG.001-2.jpeg" alt="Learn-SVG.001-2" width="600" height="400" loading="lazy">
<em>Bell example made out of different curves and straight lines</em></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">stroke</span>=<span class="hljs-string">"black"</span> <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"2"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"-45"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"7"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#4F6D7A"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"50"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#F79257"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">path</span>
      <span class="hljs-attr">d</span>=<span class="hljs-string">"
        M -50 40
        L -50 50
        L 50 50
        L 50 40
        Q 40 40 40 10
        C 40 -60 -40 -60 -40 10   
        Q -40 40 -50 40"</span>
      <span class="hljs-attr">fill</span>=<span class="hljs-string">"#FDEA96"</span>
    /&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<h2 id="heading-how-to-write-text-along-a-path">How to Write Text Along a Path</h2>
<p>Drawing shapes is not the only use case for paths. We can also use them to render text along an invisible path. We can define a path in the definitions section and use it in a <code>textPath</code> element to make the text go around the circle. Here we use arc again, but you can use any other path and the text will follow the stroke.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Screenshot-2023-11-30-at-21.21.27.png" alt="Image" width="600" height="400" loading="lazy">
<em>With the <code>text-path</code> property we can make a text follow a path</em></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">defs</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">path</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"text-arc"</span> <span class="hljs-attr">d</span>=<span class="hljs-string">"M 0, 50 A 50 50 0 1 1 1,50"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">defs</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">text</span>
    <span class="hljs-attr">fill</span>=<span class="hljs-string">"#0c5c4c"</span>
    <span class="hljs-attr">font-family</span>=<span class="hljs-string">"Tahoma"</span>
    <span class="hljs-attr">font-size</span>=<span class="hljs-string">"0.77em"</span>
    <span class="hljs-attr">font-weight</span>=<span class="hljs-string">"bold"</span>
  &gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">textPath</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#text-arc"</span>&gt;</span>
      Happy Holidays! Happy Holidays! Happy Holidays!
    <span class="hljs-tag">&lt;/<span class="hljs-name">textPath</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">text</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<h2 id="heading-how-to-animate-an-svg-with-css">How to Animate an SVG with CSS</h2>
<p>To continue our forest example, we can add a snowing effect with a similar animation. We can animate the <code>transform</code> property from CSS.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Learn-SVG.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Animation effect made with SVG and CSS</em></p>
<p>We extend our forest example with simple reusable snowflakes and add a bunch of them to the scene with various CSS classes to set some variation in speed and appearance. Then we add animation in CSS to make them look like falling snow. It’s a bit glitchy and not the most sophisticated animation, but you get the idea.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">defs</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"tree"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">polygon</span> <span class="hljs-attr">points</span>=<span class="hljs-string">"-10,0 10,0 0 -50"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#38755b"</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">line</span> <span class="hljs-attr">x2</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">y2</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#778074"</span> <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"2"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"big"</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"5"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"white"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"small"</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"3"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"white"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">defs</span>&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">rect</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-100"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-100"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#F1DBC3"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">cx</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">cy</span>=<span class="hljs-string">"380"</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"350"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#F8F4E8"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#tree"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-30"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"25"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"scale(2)"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#tree"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-20"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"40"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"scale(1.2)"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#tree"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"40"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"40"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#tree"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"50"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">transform</span>=<span class="hljs-string">"scale(1.5)"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#big"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"0"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake fast"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#big"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-50"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-20"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake fast opaque"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#big"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-40"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake fast"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#big"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"50"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-20"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake fast opaque"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#big"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"50"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake slow"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#big"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-70"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-80"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake slow opaque"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#big"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"50"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake slow"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#big"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"90"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-80"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake slow opaque"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#small"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-50"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake slow"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#small"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-50"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-60"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake slow opaque"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#small"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"30"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"70"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake slow"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">use</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#small"</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-80"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"flake slow opaque"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.flake</span> {
  <span class="hljs-attribute">animation-duration</span>: inherit;
  <span class="hljs-attribute">animation-name</span>: snowing;
  <span class="hljs-attribute">animation-iteration-count</span>: infinite;
  <span class="hljs-attribute">animation-timing-function</span>: linear;
}

<span class="hljs-selector-class">.flake</span><span class="hljs-selector-class">.opaque</span> {
  <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.7</span>;
}

<span class="hljs-selector-class">.flake</span><span class="hljs-selector-class">.slow</span> {
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">5s</span>;
}

<span class="hljs-selector-class">.flake</span><span class="hljs-selector-class">.fast</span> {
  <span class="hljs-attribute">animation-duration</span>: <span class="hljs-number">3s</span>;
}

<span class="hljs-keyword">@keyframes</span> snowing {
  <span class="hljs-selector-tag">from</span> {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(<span class="hljs-number">0</span>, -<span class="hljs-number">100px</span>);
  }
  <span class="hljs-selector-tag">to</span> {
    <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translate</span>(<span class="hljs-number">0</span>, <span class="hljs-number">100px</span>);
  }
}
</code></pre>
<h2 id="heading-how-to-make-a-clock-that-shows-the-actual-time">How to Make a Clock That Shows the Actual Time</h2>
<p>SVG elements can be manipulated from JavaScript the same way as any other HTML tag. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Screenshot-2023-11-30-at-21.21.16.png" alt="Image" width="600" height="400" loading="lazy">
<em>Clock example made with SVG and JavaScript</em></p>
<p>In this example, we are using a short code snipped to show the actual time on a clock. We access the hour and minute hands in JavaScript with <code>getElementById</code> then set their <code>transform</code> attribute with a rotation that reflects the current time. Below you see the actual SVG showing the current time.</p>
<div>
    

  

  

  

  
    
    
  

</div>

<p>For a more detailed tutorial on how to make a clock with SVG and JavaScript, check out <a target="_blank" href="https://www.freecodecamp.org/news/svg-javascript-tutorial/">How to Code an Animated Watch</a>.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">rect</span> <span class="hljs-attr">x</span>=<span class="hljs-string">"-100"</span> <span class="hljs-attr">y</span>=<span class="hljs-string">"-100"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#CD803D"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">circle</span> <span class="hljs-attr">r</span>=<span class="hljs-string">"55"</span> <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#FCCE7B"</span> <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"10"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"white"</span> /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">circle</span>
    <span class="hljs-attr">r</span>=<span class="hljs-string">"45"</span>
    <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#B6705F"</span>
    <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"6"</span>
    <span class="hljs-attr">stroke-dasharray</span>=<span class="hljs-string">"6 17.56194490192345"</span>
    <span class="hljs-attr">stroke-dashoffset</span>=<span class="hljs-string">"3"</span>
    <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span>
  /&gt;</span>

  <span class="hljs-tag">&lt;<span class="hljs-name">g</span> <span class="hljs-attr">stroke</span>=<span class="hljs-string">"#5f4c6c"</span> <span class="hljs-attr">stroke-linecap</span>=<span class="hljs-string">"round"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">line</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"hours"</span> <span class="hljs-attr">y2</span>=<span class="hljs-string">"-20"</span> <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">line</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"minutes"</span> <span class="hljs-attr">y2</span>=<span class="hljs-string">"-35"</span> <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"6"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">g</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"DOMContentLoaded"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> hoursElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"hours"</span>);
  <span class="hljs-keyword">const</span> minutesElement = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"minutes"</span>);

  <span class="hljs-keyword">const</span> hour = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getHours() % <span class="hljs-number">12</span>;
  <span class="hljs-keyword">const</span> minute = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getMinutes();

  hoursElement.setAttribute(<span class="hljs-string">"transform"</span>, <span class="hljs-string">`rotate(<span class="hljs-subst">${(<span class="hljs-number">360</span> / <span class="hljs-number">12</span>) * hour}</span>)`</span>);
  minutesElement.setAttribute(<span class="hljs-string">"transform"</span>, <span class="hljs-string">`rotate(<span class="hljs-subst">${(<span class="hljs-number">360</span> / <span class="hljs-number">60</span>) * minute}</span>)`</span>);
});
</code></pre>
<h2 id="heading-how-to-make-a-data-driven-diagram-with-svg-and-react">How to make a Data-driven Diagram with SVG and React</h2>
<p>SVGs also work well with frontend libraries. Here’s an example of a React component that generates a data-driven diagram. </p>
<p>In this example we have two things. We are generating a list of rectangles to create a column diagram based on some arbitrary data. And we also generate a series of coordinates for a polyline.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Screenshot-2023-11-30-at-21.21.32.png" alt="Image" width="600" height="400" loading="lazy">
<em>We can use JavaScript to generate a Data-Driven Diagram</em></p>
<p>For simple use cases, you can code your own diagram like this. But if you need more complex diagrams then check out the <a target="_blank" href="https://d3js.org/">D3 library</a>. The D3 library uses SVG under to hood to create all sorts of diagrams.</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Diagram</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> dataPoints = [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">7</span>, <span class="hljs-number">5</span>, <span class="hljs-number">3</span>, <span class="hljs-number">6</span>];
  <span class="hljs-keyword">const</span> sineWave = <span class="hljs-built_in">Array</span>.from({ <span class="hljs-attr">length</span>: <span class="hljs-number">115</span> })
    .map(<span class="hljs-function">(<span class="hljs-params">item, index</span>) =&gt;</span> <span class="hljs-string">`<span class="hljs-subst">${index - <span class="hljs-number">55</span>}</span>,<span class="hljs-subst">${<span class="hljs-built_in">Math</span>.sin(index / <span class="hljs-number">20</span>) * <span class="hljs-number">20</span> + <span class="hljs-number">10</span>}</span>`</span>)
    .join(<span class="hljs-string">" "</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">viewBox</span>=<span class="hljs-string">"-100 -100 200 200"</span>&gt;</span>
      {dataPoints.map((dataPoint, index) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">rect</span>
          <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
          <span class="hljs-attr">x</span>=<span class="hljs-string">{index</span> * <span class="hljs-attr">20</span> <span class="hljs-attr">-</span> <span class="hljs-attr">55</span>}
          <span class="hljs-attr">y</span>=<span class="hljs-string">{50</span> <span class="hljs-attr">-</span> <span class="hljs-attr">dataPoint</span> * <span class="hljs-attr">10</span>}
          <span class="hljs-attr">width</span>=<span class="hljs-string">"15"</span>
          <span class="hljs-attr">height</span>=<span class="hljs-string">{dataPoint</span> * <span class="hljs-attr">10</span>}
          <span class="hljs-attr">fill</span>=<span class="hljs-string">"#CD803D"</span>
        /&gt;</span>
      ))}

      <span class="hljs-tag">&lt;<span class="hljs-name">polyline</span> <span class="hljs-attr">points</span>=<span class="hljs-string">{sineWave}</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"none"</span> <span class="hljs-attr">stroke</span>=<span class="hljs-string">"black"</span> <span class="hljs-attr">stroke-width</span>=<span class="hljs-string">"5"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span></span>
  );
}
</code></pre>
<h2 id="heading-next-steps-making-svgs-interactive-with-javascript"><strong>Next Steps – Making SVGs Interactive with JavaScript</strong></h2>
<p>Under the hood, SVGs can be quite confusing at first. Lots of coordinates, letters and strange parameters. Once you understand their foundations, though, you can use them to your advantage and start coding images.</p>
<p>And we are just getting started. Adding JavaScript to the mix will introduce a whole new level.</p>
<p>For more examples check out <a target="_blank" href="https://svg-tutorial.com">svg-tutorial.com</a> or my <a target="_blank" href="https://www.youtube.com/watch?v=kBT90nwUb_o">YouTube tutorial</a> with 12 more examples on how to use SVGs for your next project!</p>
<p><a target="_blank" href="http://svg-tutorial.com">Embedded content</a></p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/kBT90nwUb_o" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h3 id="heading-subscribe-for-more-tutorials-on-web-development"><strong>Subscribe for more tutorials on Web Development:</strong></h3>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/undefined" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Generate Images using React and the Dall-E 2 API – React and OpenAI API Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ By Nishant Kumar Hey everyone! OpenAI just released its DALL-E API where users can generate custom images by just typing in a query.  So in this tutorial, you'll learn how to integrate the OpenAI DALL-E 2 API with a React app. But First, How Does Dal... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/generate-images-using-react-and-dall-e-api-react-and-openai-api-tutorial/</link>
                <guid isPermaLink="false">66d46058230dff016690582f</guid>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 08 Nov 2022 20:22:16 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/Important-Concepts-and-questions--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Nishant Kumar</p>
<p>Hey everyone! OpenAI just released its DALL-E API where users can generate custom images by just typing in a query. </p>
<p>So in this tutorial, you'll learn how to integrate the OpenAI DALL-E 2 API with a React app.</p>
<h2 id="heading-but-first-how-does-dall-e-work">But First, How Does Dall-E Work?</h2>
<p>So as you already know, you have to type a query – something like <strong>Bears with Paint Brushes in Starry Night, painted by Vincent Van Gogh</strong>. This contains so many keywords, like Paint Brushes, Starry Night, and Vincent Van Gogh.</p>
<p>What Dall-E will do is search for these images that are related to the keywords that I just mentioned above. Then it will use Artificial Intelligence to merge all the images into one, and then serve it to us.</p>
<p>Now let’s learn how you can integrate this into your React application to create your own application with these amazing features.</p>
<h2 id="heading-how-to-create-a-react-application">How to Create a React Application</h2>
<p>So, create a React application. You can create it with the CRA (create-react-app) command or you can use Vite.</p>
<p>We need a text field and a button as UI components. The text field will be used to get the query from the user and the button to trigger the API request. Let’s also create a state to store the query and a function that will run on the button click.</p>
<pre><code><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [prompt, setPrompt] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> generateImage = <span class="hljs-keyword">async</span> () =&gt; {};

  <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-main"</span>&gt;</span>
      <span class="hljs-tag">&lt;&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Generate an Image using Open AI API<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"app-input"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search Bears with Paint Brushes the Starry Night, painted by Vincent Van Gogh.."</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPrompt(e.target.value)}
          rows="10"
          cols="40"
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{generateImage}</span>&gt;</span>Generate an Image<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/&gt;</span></span>
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre><p>Our output will look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-05-212826.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-integrate-the-dall-e-2-api-with-the-react-application">How to Integrate the DALL-E 2 API with the React Application</h3>
<p>Let’s see how we can integrate the DALL-E 2 API into our application.</p>
<p>First of all, we need to go to the <a target="_blank" href="https://beta.openai.com">OpenAI</a> website. You need to sign up to generate an API key. You will also get $18 in your account that you can use.</p>
<p>Choose that you are creating an application while you are signing up.</p>
<p>So after you have created your account, go to the View API Keys section, where you can create your unique API key. Check the below image for reference.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-05-213523.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now in your React App, create a <strong>.env</strong> file. This is to store the API key.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-05-213733.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Add your API key there. Note that the method of getting the key from .env files is different in CRA and Vite React App. So please keep that in mind. I am using Vite, so this is how we do it:</p>
<pre><code>VITE_Open_AI_Key = <span class="hljs-string">"Your API Key"</span>
</code></pre><p>Now that the API key is added, we need to import a few things in our App.js or App.jsx file. These include the <strong>Configuration</strong> and <strong>OpenAIApi</strong> from <strong>openai SDK</strong>. But first, we need to install the <strong>openai SDK</strong> into the React App.</p>
<p>To install it, just type the command below:</p>
<pre><code>npm install openai
</code></pre><p>It may take some time to install. Then, import both things that we mentioned earlier like this:</p>
<pre><code><span class="hljs-keyword">import</span> { Configuration, OpenAIApi } <span class="hljs-keyword">from</span> <span class="hljs-string">"openai"</span>;
</code></pre><p>We need to create a configuration variable, which will take the API key from the .env file.</p>
<pre><code><span class="hljs-keyword">const</span> configuration = <span class="hljs-keyword">new</span> Configuration({
    <span class="hljs-attr">apiKey</span>: <span class="hljs-keyword">import</span>.meta.env.VITE_Open_AI_Key,
});
</code></pre><p>Now, we need to pass this configuration instance to the OpenAIApi, and create a new instance for OpenAIApi.</p>
<pre><code><span class="hljs-keyword">const</span> openai = <span class="hljs-keyword">new</span> OpenAIApi(configuration);
</code></pre><p>Here is the whole code until now:</p>
<pre><code><span class="hljs-keyword">import</span> { Configuration, OpenAIApi } <span class="hljs-keyword">from</span> <span class="hljs-string">"openai"</span>;

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">"./App.css"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [prompt, setPrompt] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> configuration = <span class="hljs-keyword">new</span> Configuration({
    <span class="hljs-attr">apiKey</span>: <span class="hljs-keyword">import</span>.meta.env.VITE_Open_AI_Key,
  });

  <span class="hljs-keyword">const</span> openai = <span class="hljs-keyword">new</span> OpenAIApi(configuration);


  <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-main"</span>&gt;</span>
      <span class="hljs-tag">&lt;&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Generate an Image using Open AI API<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"app-input"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search Bears with Paint Brushes the Starry Night, painted by Vincent Van Gogh.."</span>
          <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setPrompt(e.target.value)}
          rows="10"
          cols="40"
        /&gt;
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{generateImage}</span>&gt;</span>Generate an Image<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/&gt;</span></span>
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre><p>Now in the <strong>generateImage</strong> function, we need to call the OpenAIApi instance that we created before. Remember, the function needs to be asynchronous.</p>
<pre><code><span class="hljs-keyword">const</span> generateImage = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">await</span> openai.createImage({
      <span class="hljs-attr">prompt</span>: prompt,
      <span class="hljs-attr">n</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">size</span>: <span class="hljs-string">"512x512"</span>,
    });
  };
</code></pre><p>As you can see, we are using <strong>openai.createImage</strong>. This API is used to create an image using a user query. It also takes <strong>n</strong>, which is the number of images we want the API to return, and the <strong>size of the image</strong>. </p>
<p>There are three different image sizes with different prices, which are listed below. If you are using 1024x1024 size, it will cost you $0.020 per image.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-05-215314.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now this <strong>openai.createImage</strong> returns some response that we can store in a variable. We can then get the generated image link from the response variable.</p>
<pre><code><span class="hljs-keyword">const</span> generateImage = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> openai.createImage({
      <span class="hljs-attr">prompt</span>: prompt,
      <span class="hljs-attr">n</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">size</span>: <span class="hljs-string">"512x512"</span>,
    });

    <span class="hljs-built_in">console</span>.log(res.data.data[<span class="hljs-number">0</span>].url);
  };
</code></pre><p>But let’s not do that. Let’s create one more state to store this image link so that we can view the image in the UI itself.</p>
<pre><code><span class="hljs-keyword">const</span> [result, setResult] = useState(<span class="hljs-string">""</span>);

<span class="hljs-keyword">const</span> generateImage = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> openai.createImage({
      <span class="hljs-attr">prompt</span>: prompt,
      <span class="hljs-attr">n</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">size</span>: <span class="hljs-string">"512x512"</span>,
    });

    setResult(res.data.data[<span class="hljs-number">0</span>].url);
  };
</code></pre><p>Now the image link will be stored inside the <strong>result</strong> state. Let's also render the image in the UI. But as the result is initially empty, we can create a check. We will only see the image tag where there is a link inside the state.</p>
<pre><code>{result.length &gt; <span class="hljs-number">0</span> ? (
          <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"result-image"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{result}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"result"</span> /&gt;</span></span>
        ) : (
          <span class="xml"><span class="hljs-tag">&lt;&gt;</span><span class="hljs-tag">&lt;/&gt;</span></span>
        )}
</code></pre><p>And here's the styling too:</p>
<pre><code>.result-image {
  margin-top: <span class="hljs-number">20</span>px;
  width: <span class="hljs-number">350</span>px;
}
</code></pre><p>The UI will now look something like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-05-220108.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's type something and see the output:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-05-220222.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In the above example, I have typed <strong>A Horse on the Beach with Red Sands.</strong> And here is the result.</p>
<p>Let's try something more complex, like <strong>Bears with Paint Brushes in Starry Night, painted by Vincent Van Gogh.</strong> </p>
<p>Here is the result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-05-220423.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This is how you do it. You can type any input query and it will generate that image through Artificial Intelligence. </p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>And that’s all folks. Now you know how to create your own React application with the DALL-E 2 API to generate images using AI. There are a lot more functionalities that you can add. So go ahead and experiment a little.</p>
<p>If you want to see the video version of this, check my video on <a target="_blank" href="https://youtu.be/oacBV4tnuYQ">Generate Images using React and Dall-E API - React and OpenAI API Tutorial</a> on my YouTube channel <a target="_blank" href="https://www.youtube.com/c/CybernaticoByNishant">Cybernatico</a>.</p>
<p>Check the code on <a target="_blank" href="https://github.com/nishant-666/Dall-E-API-with-React">GitHub</a> for your reference.</p>
<blockquote>
<p>Happy Learning.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ HTML Background Image – How to Add Wallpaper Images to Your Website ]]>
                </title>
                <description>
                    <![CDATA[ Background images can help beautify websites and make them more attractive to users.  In this article, you'll learn:  How to add a background image to your website using the CSS background-image property.  Other CSS background properties for images.... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/html-background-image-how-to-add-wallpaper-images-to-your-website/</link>
                <guid isPermaLink="false">66b0a2f45e73cf343a5cc014</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ihechikara Abba ]]>
                </dc:creator>
                <pubDate>Fri, 23 Sep 2022 19:18:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/jonatan-pie-3l3RwQdHRHg-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Background images can help beautify websites and make them more attractive to users. </p>
<p>In this article, you'll learn: </p>
<ul>
<li>How to add a background image to your website using the CSS <code>background-image</code> property. </li>
<li>Other CSS background properties for images.</li>
</ul>
<h2 id="heading-how-to-add-wallpaper-images-to-your-website">How to Add Wallpaper Images to Your Website</h2>
<p>When coding a website, using an image as the background image of the website is different from inserting an image in HTML using the <code>img</code> element.</p>
<p>To use an image as the background of your website, you'll use CSS. </p>
<p>Here's an example: </p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"style.css"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Background Image<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Background image<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span>{
    <span class="hljs-attribute">text-align</span>: center;
}
</code></pre>
<p>We have two code blocks above — the HTML code displays text that says "Background image" on the webpage while the CSS code centers the text on the page. </p>
<p>To add a wallpaper image to the website — one that covers the entire page — you have to write some CSS rules for the <code>body</code> element. Here's how: </p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span>{
    <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">'bg-image.jpg'</span>);
}
</code></pre>
<p>In the code above, we're using the <code>background-image</code> property to add an image to the body of the webpage. The path/location of the image is passed in as a parameter to the <code>url()</code> function: <code>url('bg-image.jpg')</code>. </p>
<p>Here's what the webpage looks like now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/full-bg-image.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-what-if-the-background-image-is-smaller-than-the-browser-window">What if the Background Image Is Smaller Than the Browser Window?</h2>
<p>In situations where the image is smaller than the browser, the image is repeated a couple 0f time to cover up the spaces that remain. </p>
<p>This repetition doesn't look great for every picture. Here's what a smaller version of the image used in the previous section looks like in the browser: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/repeat.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The image has been split into four uneven parts. Unless this is the effect you're looking for, you can fix it using the <code>background-repeat</code> property. </p>
<p>Here's how to fix the image repetition problem:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span>{
    <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">'bg-image-small.jpg'</span>);
    <span class="hljs-attribute">background-repeat</span>: no-repeat;
}
</code></pre>
<p>In the code above, we assigned a <code>no-repeat</code> value to the <code>background-repeat</code> property.</p>
<p>Here's what the webpage looks like now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/small-image.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The image is no longer being repeated across the page but we have a new problem — the image no longer covers the whole page.  </p>
<p>To fix that, we use the <code>background-size</code> and <code>background-attachment</code> properties:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span>{
    <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">'bg-image-small.jpg'</span>);
    <span class="hljs-attribute">background-repeat</span>: no-repeat;
    <span class="hljs-attribute">background-size</span>: cover;
    <span class="hljs-attribute">background-attachment</span>: fixed;
}
</code></pre>
<p>Setting the value of the <code>background-size</code> property to <code>cover</code> makes the image cover the whole element (the <code>body</code>/entire page in our case). </p>
<p>With the <code>fixed</code> value of the <code>background-attachment</code> property, the image's position is fixed. This way it remains in the same position even when you scroll across the page. </p>
<p>Here's the image now:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/cover-image.PNG" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The downside of stretching out a small image to cover the entire page is that the image loses quality and becomes blurry as its being stretched. In this case, you should consider that before using a small image as the background image for your website. </p>
<h2 id="heading-summary">Summary</h2>
<p>In this article, we talked about adding wallpaper images to a website. </p>
<p>You can add a background image to your website using the CSS <code>background-image</code> property.</p>
<p>We also learned how to use other CSS background properties like <code>background-repeat</code>, <code>background-size</code>, and <code>background-attachment</code>. </p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Alt Text? Image Alt Text HTML Example ]]>
                </title>
                <description>
                    <![CDATA[ Images play a significant role on our web pages. They help explain concepts better, make our web pages visually attractive, and lots more. In HTML, you use the <img> tag to embed an image into your web page. This <img> tag has two required attributes... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-alt-text-image-alt-text-html-example/</link>
                <guid isPermaLink="false">66d46008d14641365a050909</guid>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Joel Olawanle ]]>
                </dc:creator>
                <pubDate>Fri, 16 Sep 2022 20:39:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/cover-template--1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Images play a significant role on our web pages. They help explain concepts better, make our web pages visually attractive, and lots more.</p>
<p>In HTML, you use the <code>&lt;img&gt;</code> tag to embed an image into your web page.</p>
<p>This <code>&lt;img&gt;</code> tag has two required attributes: <code>src</code> to specify the path to the image, and <code>alt</code> to specify an alternate text for the image. The <code>alt</code> attribute is there in case, for some reason (maybe wrong image path), the image doesn't get displayed.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/my-image.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"This is the alt text for my image"</span>&gt;</span>
</code></pre>
<p>Although the <code>alt</code> attribute is required in the <code>&lt;img&gt;</code> tag, many people decide to leave it empty or type some text that doesn't not correlate with the image to make sure it has text.</p>
<p>Most developers pay little or no attention to the alt text because they don't know its usefulness, and most tutorials fail to highlight its importance.</p>
<p>In this article, you will understand what alt text means, what it does, and how useful it is when embedding an image in your webpage. We will also highlight a few points to consider when writing alt text for your images.</p>
<h2 id="heading-what-is-alt-text">What is Alt Text?</h2>
<p>Alternative or alt text is also referred to as an alt attribute. It is concise, descriptive text that accurately describes an image.</p>
<p>By default, this text is not shown when you view a web page in the browser. Still, in a situation where you cannot view an image for some reason, the alt text becomes visible. This text should be informative and descriptive enough to give the reader or user a sense of what the image is about and what message it conveys.</p>
<p>For example, if you have an image like this:</p>
<p><img src="https://paper-attachments.dropbox.com/s_95E44C54B681F0DAF38695280E5CE127D3338A54647F8EF9DBA670394BC64304_1663348516195_cat.avif" alt="Image by Erik-Jan Leusink on Unplash" width="600" height="400" loading="lazy"></p>
<p>Rather than giving it a random alt text like "cat" or "Sleeping cat", you can be more descriptive and specific by adding alt text like "A Cat sleeping on a blanket" or "A Cat dozing on on a blanket".</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/imgs/cat-sleeping.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"A Cat sleeping on a blanket"</span>&gt;</span>
</code></pre>
<h2 id="heading-why-is-image-alt-text-important">Why is Image Alt Text Important?</h2>
<p>The alt attribute is required for the <code>&lt;img&gt;</code> tag, which is one reason you should add it to your images.</p>
<p>But there are several other reasons why you should not only consider adding alt text but rather descriptive and informative alt text to your images:</p>
<ol>
<li><p>When you have connectivity issues or your image's path is incorrectly declared, your image may not be loaded to your webpage. In this case, the alt text value is shown in the place of the image.</p>
</li>
<li><p>The alt text provides the descriptive meaning of an image that search engines can use to improve your web page's SEO. It gives search engines better information to rank your web page with, meaning having proper alt text will help your web page rank higher.</p>
</li>
<li><p>Visually impaired users who use screen readers can hear a description of the image. This shows how useful it is to enhance accessibility for people who can't see the screen.</p>
</li>
<li><p>When you want to link your image to another page or document, the alt text is used as the anchor text when the image fails to load.</p>
</li>
</ol>
<h2 id="heading-tips-for-writing-good-alt-text">Tips for Writing Good Alt Text</h2>
<p>A famous saying is that "anything worth doing is worth doing well". The same basically applies to writing your alt text – it is better not to write alt text than to write bad or meaningless alt text.</p>
<p>Here are a few tips to bear in mind when writing your alt text:</p>
<h3 id="heading-accurately-describe-the-image">Accurately describe the image</h3>
<p>The main aim of writing alt text is that it is able to stand as an alternative for an image (like when the images fail to display or for screen readers).</p>
<p>For alt text to serve its purpose, it must adequately and accurately describe the image.</p>
<p>One helpful tip is to think of a way to describe an image to a user who cannot see the image or as if you were describing it to someone over the phone. Then write the alt text that way.</p>
<h3 id="heading-keep-it-short">Keep it short</h3>
<p>At this point, you might begin to think that these alt texts would end up being in the form of a paragraph – but they should't be. In most cases, we should always look for the best way to explain and describe our images in a few words.</p>
<p>Always remember that screen readers may cut off alt text at around 125 characters, so it's best to stick within that limit. Still, you should also always avoid using a single word as alt text.</p>
<p>For example, in the image below, we can see a man standing on an elevated rock looking at the sky with his hands stretched out:</p>
<p><img src="https://images.unsplash.com/photo-1454942901704-3c44c11b2ad1?ixlib=rb-1.2.1&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1000&amp;q=80" alt="image by Joshua Earle on unsplash" width="1000" height="667" loading="lazy"></p>
<p>A poor alt text would be "Man standing" or "Man looking at sky". Better alt text would involve adding more descriptive information like "Man standing on top of rock mountain during golden hour" or "Man standing on top of a rock mountain and looking at the sky", and so on.</p>
<p><strong>Note:</strong> There are always many ways to describe an image, but always think of a better way to describe your images to someone who cannot see the image, making your text short but precise.</p>
<h3 id="heading-use-keywords-but-avoid-keyword-stuffing">Use keywords but avoid keyword stuffing</h3>
<p>When describing an image, the keyword should not be your top priority. Instead, you should focus on truthfully describing your image.</p>
<p>Although having your keywords in your alt text will help your web page rank higher on search engines, it is essential to know that search engines can't recognize unhelpful or bad alt text. And if you have excessive keywords in your alt text (keyword stuffing) it can make your web page rank low.</p>
<p>This means you should only to use important images that enhance the essence of your web page and only use the most important keywords to describe them.</p>
<h3 id="heading-dont-repeat-yourself">Don't repeat yourself</h3>
<p>Avoid repetition by all means. Why would you use your web page title or heading as alt text? It's better to leave it empty than repeat captions or web content.</p>
<p>The best advice is, when you cannot describe an image well, it's best to leave the alt text empty than add any random text or use image captions as alt text which is repetition.</p>
<h4 id="heading-image-captions-vs-alt-text">Image Captions vs. Alt Text</h4>
<p>It's easy to confuse image captions and alt text or repeat the content in your alt text as an image caption.</p>
<p>Captions describe images to help users relate to surrounding text, whereas alternative text explains the information in an image or describes an image for screen reader users.</p>
<p>Captions do not have to exactly match what the image shows but rather they explain how the image relates to the text or content in which it is placed.</p>
<h3 id="heading-dont-include-the-words-image-or-picture">Don't include the words' image' or 'picture'</h3>
<p>The alt attribute is used in an image tag, which means search engines will know that this is an image, so there is no need to use the word image or picture when writing alt texts.</p>
<p>However, it's good to help people understand the context or what type of image or picture it is. For example, you could say headshot, illustration, screenshot, chart, and lots more.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In this article, you have learned what alt text means and why it's essential. You've also seen some important tips on how to use it when embedding images on your web page.</p>
<p>Finally, it is essential to note that you should always add alt text to your images, including your logo, images used as buttons, and many others – and it's crucial to know why uou're doing this.</p>
<p>But note that decorative images, whose primary purpose is to decorate your web pages rather than pass information, do not require alt text.</p>
<p>Thanks for reading, and ensure you have fun coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Google Sheets Tutorial – How to Use Regex and VLOOKUP to Display Images from Google Drive ]]>
                </title>
                <description>
                    <![CDATA[ Images make many things better. And Google Sheets is one of those things.  The easiest way to add an image to Google Sheets is to simply insert one into your sheet.  But if you have added many images this way, you'll quickly tire of the multiple clic... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/google-sheets-use-regex-and-vlookup-to-display-images-from-google-drive/</link>
                <guid isPermaLink="false">66b8ddf8abe19f6180038a33</guid>
                
                    <category>
                        <![CDATA[ google sheets ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Regex ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Regular Expressions ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Eamonn Cottrell ]]>
                </dc:creator>
                <pubDate>Wed, 03 Aug 2022 17:03:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/google-sheets-regex.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Images make many things better. And Google Sheets is one of those things. </p>
<p>The easiest way to add an image to Google Sheets is to simply insert one into your sheet. </p>
<p>But if you have added many images this way, you'll quickly tire of the multiple clicks it takes to do so. Especially if you have to add images often, or if you have to add the same images to multiple sheets.</p>
<p>In this article, you'll learn how to add many images from their URLs that you can dynamically toggle between in a dropdown list. We'll cover:</p>
<ul>
<li>Data Validation for creating a dropdown list</li>
<li>Named Ranges to make formula references easier and cleaner</li>
<li>The VLOOKUP function to display the right image from the dropdown list</li>
<li>The REGEXEXTRACT function to extract a string from a URL (don't worry, it'll make sense 😉)</li>
<li>The IMAGE function to display the image from a URL address</li>
<li>We'll use the ampersand (&amp;) operator as well as regular expressions (Regex)</li>
<li>We'll also make our sheet look good by removing gridlines, changing the font, adding borders, colors, and a drop shadow effect behind tables</li>
</ul>
<h2 id="heading-how-to-setup-the-project">How to Setup the Project 📐</h2>
<p>You can follow along with the sheet I'm using for everything we'll discuss:</p>
<p><a target="_blank" href="https://docs.google.com/spreadsheets/d/1rFU2gPy6rU8IKFDmsxKHYCf0KGVHkcumQ5O5QCf156M/edit?usp=sharing">https://docs.google.com/spreadsheets/d/1rFU2gPy6rU8IKFDmsxKHYCf0KGVHkcumQ5O5QCf156M/edit?usp=sharing</a></p>
<p>Make a copy if you want to edit it yourself.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/copy.png" alt="Image" width="600" height="400" loading="lazy">
<em>Make a copy to edit yourself</em></p>
<p>All cell and range references below will be from this sheet so you can easily look and see what I'm talking about.</p>
<p>I've also made a folder of images <a target="_blank" href="https://drive.google.com/drive/folders/1na_BdarFXheF5t6YssKY2qPfTEDLYlSF?usp=sharing">here</a> that is publicly shared so all this works. You don't have to make a copy of this unless you just want to 😀.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/visible.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-use-named-ranges-in-google-sheets">How to Use Named Ranges in Google Sheets 📛</h2>
<p>Named ranges make life easier. </p>
<p>You don't <em>have</em> to use them, but it makes references in functions easier since you'll be writing the name of something instead of a sterile cell reference.</p>
<p>We'll use three of them:</p>
<ol>
<li><code>B4</code> = <code>itemSelect</code> This is the cell where our dropdown list will live.</li>
<li><code>B8:G13</code> = <code>pictureMatch</code> This is the range for our VLOOKUP function. It contains the names of the pictures we'll display followed by their respective URLs.</li>
<li><code>B8:B16</code> = <code>pictureName</code> This is the first column of the <code>pictureMatch</code> range for referencing just the names in our data validation cell.</li>
</ol>
<p>To create a named range, simply highlight the range, select Data -&gt; Named ranges from the toolbar, and name it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/named.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-perform-data-validation">How to Perform Data Validation 📃</h2>
<p>We'll use data validation to create a dropdown list in B4. Same deal here – just highlight the cell (or range) and select Data -&gt; Data validation from the toolbar:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/validation.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Select List from a range, and then <code>=pictureName</code> (because we named that range) for the range. Alternatively, you can declare the range explicitly.</p>
<p>There are additional options to configure if you want to change anything:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-8.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you select reject input, you can have a custom message pop up whenever an invalid choice is entered:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-7.png" alt="Image" width="600" height="400" loading="lazy">
<em>You might want to make your message more helpful than this one.</em></p>
<h2 id="heading-how-to-use-vlookup">How to Use VLOOKUP 📊</h2>
<p>VLOOKUP is an incredibly useful function. It takes four arguments: </p>
<pre><code>=VLOOKUP(search_key, range, index, [is_sorted])

=VLOOKUP(itemSelect,pictureMatch,<span class="hljs-number">3</span>,<span class="hljs-number">0</span>)
</code></pre><p>We'll use <code>itemSelect</code> for our <code>search_key</code> and <code>pictureMatch</code> for the range because we want to find <code>itemSelect</code> in that range. Then the 3 for index gets the value in the third column in that range. </p>
<p>(It's 3 in our example because we merged the cells in columns B &amp; C for our formatting, but VLOOKUP still counts both of them).</p>
<p>Finally, the zero sets <code>is_sorted</code> to <code>FALSE</code>. Our data is not sorted, and we want an exact match.</p>
<h2 id="heading-how-to-use-regexextract">How to Use REGEXEXTRACT 💾</h2>
<p>It happened: I found a real world use for Regular Expressions. 😳</p>
<p><a target="_blank" href="https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/regular-expressions/">This section of freeCodeCamp's Javascript certification</a> was particularly confusing for me, and it was good to revisit a small portion of it here in the wild.</p>
<p>Because Google Drive is quirky, and we're sort of hacking a free option here, we need to alter the URLs to our images in order for the IMAGE function to work properly.</p>
<p><a target="_blank" href="https://stackoverflow.com/questions/60287504/how-display-images-from-google-drive-on-gsheet-cell">This</a> Stack Overflow answer was helpful for me.</p>
<p>We need to build a URL by taking this:</p>
<pre><code class="lang-javascript">https:<span class="hljs-comment">//drive.google.com/uc?export=download&amp;id=###</span>
</code></pre>
<p>and replacing the ### part at the end with the ID we extract with the <code>REGEXEXTRACT</code> function.</p>
<p>Looking at the URLs we copied over, we can see a pattern. Everything after the <code>/d/</code> and then before the next <code>/</code> is the ID. </p>
<p>Here's an example of one of our image URLs: <a target="_blank" href="https://drive.google.com/file/d/1IaO08gj3GWIUQDAnzKEob62Gcl87ufuN/view?usp=sharing"><code>https://drive.google.com/file/d/1IaO08gj3GWIUQDAnzKEob62Gcl87ufuN/view?usp=sharing</code></a></p>
<p>You can see this at work by itself in <code>B26</code> of the example spreadsheet as the function grabs everything between those two markers:</p>
<p><code>=REGEXEXTRACT(D9,".*/d/(.*)/")</code></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-9.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-10.png" alt="Image" width="600" height="400" loading="lazy">
<em>This extracts everything between the /d/ and the /</em></p>
<h2 id="heading-how-to-use-the-image-function">How to Use the IMAGE Function 📷</h2>
<p>Okay. We've got the disparate pieces figured out. I know the pieces fit. 🎵 </p>
<p>Let's put them together.</p>
<p>All of our work was to get one cell ( <code>B4</code> ) to provide data to the <code>IMAGE</code> function.</p>
<p>Image takes one argument and three other optional ones: </p>
<pre><code class="lang-javascript"> IMAGE(url, [mode], [height], [width])
</code></pre>
<p>We build the URL by combining the required beginning of the URL which I've got in <code>J17</code> using the ampersand (&amp;) operator with our <code>REGEXEXTRACT</code> function. And within our <code>REGEXEXTRACT</code> function we use our <code>VLOOKUP</code> function to get the URL of whatever image we've selected in the <code>itemSelect</code> cell.</p>
<p>Whew. </p>
<p>But, cool, right!?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/giphy-1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If you feel lost in a recursive nightmare, I encourage you to pull up the <a target="_blank" href="https://docs.google.com/spreadsheets/d/1rFU2gPy6rU8IKFDmsxKHYCf0KGVHkcumQ5O5QCf156M/edit?usp=sharing"><strong>example spreadsheet</strong></a> and examine the parts of the function in <code>F4</code> piece by piece. 👍</p>
<h2 id="heading-how-to-format-your-sheet-ftw">How to Format Your Sheet FTW 💯</h2>
<p>These few details can <strong>turn up the volume 📣</strong> on an otherwise mundane spreadsheet.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/nin2.gif" alt="Image" width="600" height="400" loading="lazy">
<em>This is likely the only place you'll find a NIN gif in an article about spreadsheets today.</em></p>
<p>I love a hard drop shadow, and we can achieve this by manipulating the row and column sizes around a particular cell or range, using the merge cell option for our main range, and then using a fill color around the right side and bottom.</p>
<p>Click the lines between the column headers to drag and adjust the widths and heights of the columns and rows.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/width.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Cells are the main appeal of spreadsheets, but in some cases hiding the gridlines can make your sheet standout. I opted for this approach in this project. </p>
<p>Select View-&gt;Show-&gt;Gridlines.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/gridlines.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>As much as I appreciate Arial, I will typically opt out of the default font immediately. </p>
<p>Click the Font Dropdown in the Toolbar. It's usually smack dab in the middle:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/fonts.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And just choose whatever font you'd like.</p>
<p>There you have it!</p>
<h2 id="heading-thanks-for-reading">Thanks for Reading! 🙏</h2>
<p>Follow me on Twitter to see more content like this: <a target="_blank" href="https://twitter.com/EamonnCottrell">https://twitter.com/EamonnCottrell</a></p>
<p>Thanks!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/thankyou.gif" alt="Image" width="600" height="400" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is an SVG File? ]]>
                </title>
                <description>
                    <![CDATA[ SVG stands for scalable vector graphics. It's a web-friendly vector-based file format used to render two-dimensional images on the internet. You can identify SVG files by their extension – .svg. Unlike other popular image formats like PNG, JPEG, and ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-an-svg-file/</link>
                <guid isPermaLink="false">66adf26388723f64bc4313a3</guid>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SVG ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kolade Chris ]]>
                </dc:creator>
                <pubDate>Wed, 01 Jun 2022 16:05:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/06/svg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>SVG stands for scalable vector graphics. It's a web-friendly vector-based file format used to render two-dimensional images on the internet.</p>
<p>You can identify SVG files by their extension – <code>.svg</code>.</p>
<p>Unlike other popular image formats like PNG, JPEG, and JPG – which store image information in form of pixels because they are raster-based formats – SVGs store graphics information as a set of points and lines.</p>
<p>This means no matter how SVG files are reworked, zoomed, or resized, they don’t become blurred and pixelated like PNG, JPG, and other raster images.</p>
<p>This article will show you the possibilities of SVG image files and how you can make one for yourself by coding it.  </p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-how-to-make-an-svg-file">How to Make an SVG File</a><ul>
<li><a class="post-section-overview" href="#heading-how-to-make-an-svg-with-image-editing-programs">How to Make an SVG with Image Editing Programs</a> </li>
<li><a class="post-section-overview" href="#heading-how-to-make-an-svg-with-xml">How to Make an SVG with XML </a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-what-is-an-svg-file-used-for">What is an SVG File Used for?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-open-an-svg-file">How to Open an SVG File </a></li>
<li><a class="post-section-overview" href="#heading-how-do-i-convert-an-svg-file-to-an-image">How do I Convert an SVG File to an Image?</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-how-to-make-an-svg-file">How to Make an SVG File</h2>
<h3 id="heading-how-to-make-an-svg-with-image-editing-programs">How to Make an SVG with Image Editing Programs</h3>
<p>You can make an SVG file with image editing software like Adobe Illustrator, CorelDraw, Adobe Photoshop, Microsoft Visio, and GIMP.</p>
<p>With these programs, your creativity is your limit when it comes to the SVGs you can draw. </p>
<p>It depends on how knowledgeable and experienced you are with the programs.</p>
<p>In addition, if you create an illustration and drawings with Google Docs, you can export them to SVG.</p>
<h3 id="heading-how-to-make-an-svg-with-xml">How to Make an SVG with XML</h3>
<p>If you don’t know how to use the image editing programs listed above but you can code, you can code up an SVG with XML.</p>
<p>To code an SVG, create a file with the <code>.svg</code> extension:
<img src="https://www.freecodecamp.org/news/content/images/2022/06/ss1.png" alt="ss1" width="600" height="400" loading="lazy"></p>
<p><strong>Step 1</strong>: Define your SVG opening and closing tags</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span>&gt;</span>
    <span class="hljs-comment">&lt;!--  --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<p><strong>Step 2</strong>: Define the version and <code>xmlns</code> attributes inside the opening tag and set both to <code>1.1</code> and <code>"http://www.w3.org/2000/svg"</code> respectively.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">version</span>=<span class="hljs-string">"1.1"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<p><strong>Step 3</strong>: Specify the shape you want to draw in a self-closing tag. For example, <code>&lt;rect&gt;</code> for rectangle.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">version</span>=<span class="hljs-string">"1.1"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">rect</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<p><strong>Step 4</strong>: Specify the width and height you want:</p>
<pre><code class="lang-xml"> width="200" height="100"
</code></pre>
<p><strong>Step 5</strong>: Define the color with which you want to fill the shape with the <code>fill</code> attribute:</p>
<pre><code class="lang-xml">fill="#2ecc71"
</code></pre>
<p>The code now looks as shown in the snippet below:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">version</span>=<span class="hljs-string">"1.1"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">rect</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#2ecc71"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<p>And at the end, this is what shows in the browser:
<img src="https://www.freecodecamp.org/news/content/images/2022/06/ss2.png" alt="ss2" width="600" height="400" loading="lazy"></p>
<p>You can also define border-radius on the <code>x</code> and <code>y</code> axis with the <code>rx</code> and <code>ry</code> attributes:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">version</span>=<span class="hljs-string">"1.1"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">rect</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#2ecc71"</span> <span class="hljs-attr">rx</span>=<span class="hljs-string">"4"</span> <span class="hljs-attr">ry</span>=<span class="hljs-string">"4"</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/06/ss3.png" alt="ss3" width="600" height="400" loading="lazy"></p>
<p>After drawing the SVG, you can then use it as the value for the source (<code>src</code>) of an image:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"svgdraw.svg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"A rectangle made with SVG"</span> /&gt;</span>
</code></pre>
<p>If you want, you can embed the SVG straight into your HTML code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">svg</span> <span class="hljs-attr">version</span>=<span class="hljs-string">"1.1"</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://www.w3.org/2000/svg"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">rect</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"200"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"100"</span> <span class="hljs-attr">fill</span>=<span class="hljs-string">"#2ecc71"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">svg</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
</code></pre>
<h2 id="heading-what-is-an-svg-file-used-for">What is an SVG File Used for?</h2>
<p>Because SVG files remain the same for life, website icons and logos are usually made with them. </p>
<p>An excellent advantage of SVG is that the text in them can be read by search engines like Google, so SVG files are used for making infographics and illustrations.</p>
<h2 id="heading-how-to-open-an-svg-file">How to Open an SVG File</h2>
<p>Modern browsers like Google Chrome, Edge, Safari, and Firefox have built-in functionalities that make them open SVG files for you.     </p>
<p>You can also open SVG files in specialized editing software you can use to make them. Again, examples are Adobe Illustrator, CorelDraw, Adobe Photoshop, Microsoft Visio, and GIMP.</p>
<p>If you want to edit SVG files, you can open them with a Code Editor like VS Code, Atom, and Sublime Text then make your edits.</p>
<h2 id="heading-how-do-i-convert-an-svg-file-to-an-image">How do I Convert an SVG File to an Image?</h2>
<p>If you want to convert an SVG to other image formats like PNG, and JPG, you can use image editing programs like Adobe Photoshop.</p>
<p>You can also use an online tool called <a target="_blank" href="https://convertio.co/svg-png/">Convertio</a>.</p>
<p>All you need to do is to upload your SVG, then select the format you want to convert it to.
<img src="https://www.freecodecamp.org/news/content/images/2022/06/ss4.png" alt="ss4" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>There are a lot of reasons why you should be using SVG.</p>
<p>My favorite of all those reasons is that search engines can read the text on SVG files. This is because SVG files are written in pure XML – the markup language for transmitting digital data.</p>
<p>If Google and other search engines find relevant keywords in the SVG files, it can lead to a massive boost in SEO.</p>
<p>Thank you for reading.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Make an Image Search App in React using the Unsplash API ]]>
                </title>
                <description>
                    <![CDATA[ Unsplash is a site where you can download free and unlicensed images and use them as you see fit. In this tutorial, we will make an Image Search App using the Unsplash API to get access to its enormous collection of images and also download them. Bef... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-make-an-image-search-app-in-react/</link>
                <guid isPermaLink="false">66d45d9ac7632f8bfbf1e3d3</guid>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ateev Duggal ]]>
                </dc:creator>
                <pubDate>Mon, 04 Apr 2022 22:19:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/04/Unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Unsplash is a site where you can download free and unlicensed images and use them as you see fit.</p>
<p>In this tutorial, we will make an Image Search App using the Unsplash API to get access to its enormous collection of images and also download them.</p>
<p>Before starting the development part of our app, let’s see how it will <a target="_blank" href="https://unspalsh-app-in-react.vercel.app/">look exactly</a>.</p>
<p>Let’s start…</p>
<h2 id="heading-contents">Contents</h2>
<ol>
<li><p>How to Create the React App</p>
</li>
<li><p>How to Build the UI of our App</p>
</li>
<li><p>How to Get the Access Key and API Endpoint from Unsplash</p>
</li>
<li><p>How to Use Hooks in our App</p>
</li>
<li><p>How to Display Images in our App</p>
</li>
<li><p>How to Handle Errors</p>
</li>
<li><p>Conclusion</p>
</li>
</ol>
<h3 id="heading-what-will-we-learn">What will we learn?</h3>
<p>This project is mainly for beginners, but anyone who wants to brush up their skills can follow along. In this tutorial, you will learn:</p>
<ol>
<li><p>How to get API endpoints and Access Keys from the Unsplash developer's dashboard.</p>
</li>
<li><p>How to use the useState and useEffect hooks to fetch data from the API.</p>
</li>
<li><p>How to use the map function to display images or any other data from the API.</p>
</li>
</ol>
<h2 id="heading-how-to-create-the-react-app">How to Create the React App</h2>
<p>It's very easy to create a React app – just go to your working directory in your preferred IDE and enter the following command in the terminal:</p>
<pre><code class="lang-javascript">npx create-react-app image-search-app
</code></pre>
<p>If you are unsure how to properly set up a create-react-app project, you can refer to the official guide here at <a target="_blank" href="https://create-react-app.dev/docs/getting-started/">create-react-app-dev</a>.‌‌</p>
<p>After the setup, run npm start in the same terminal to start localhost:3000 where our React app will be hosted. We can also see all our changes there.</p>
<h2 id="heading-how-to-build-the-ui-of-our-app">How to Build the UI of our App</h2>
<p>There will be two sections in the UI of our App:</p>
<ol>
<li><p>The Input section</p>
</li>
<li><p>The Result section where we will show the images</p>
</li>
</ol>
<p>In the input section, we have an input tag in which we will write the search term or query. We also have a button with an <strong>onClick</strong> event handler which will trigger the function responsible for fetching the data from the API.</p>
<pre><code class="lang-html">import React from "react";
const App = () =&gt; {
  return (
    <span class="hljs-tag">&lt;&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container-fluid"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"row"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-12 d-flex justify-content-center align-items-center input"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"col-3 form-control-sm py-1 fs-4 text-capitalize border border-3 border-dark"</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
              <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search Anything..."</span>
            /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{Submit}</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"btn bg-dark text-white fs-3 mx-3"</span>
            &gt;</span>
              Search
            <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;/&gt;</span>
  );
};
export default App;
</code></pre>
<p>The output will be the following:</p>
<p><img src="https://lh4.googleusercontent.com/qzIWk69MB4RvIfXj7neJ3mhg1q3G1S96r42xsyVFIEcU7IUXBUiT4H7dMP7mSDDHiVOtM1LAycPF2DO5pN6_wanvWbgyED1K3YmeXvE7uNuiYYImV8e7CNXGY4kB0_9B8du3Qxi2" alt="Image" width="600" height="400" loading="lazy"></p>
<p>In this article, we will not be discussing the styling part of the app. This way we can stay more focused on the React part which is more necessary to understand.</p>
<h2 id="heading-how-to-get-the-access-key-and-api-endpoint-from-unsplash">How to Get the Access Key and API Endpoint from Unsplash</h2>
<p>Let's get those API keys from <a target="_blank" href="https://unsplash.com/developers">Unsplash for Developer</a>. follow the steps given below to get your API key and other details:</p>
<p>First, go to the above link and click register as a developer.</p>
<p><img src="https://lh6.googleusercontent.com/xB8Tb3HKYAGv5b7ArmtT6zuU3aGTF_uO6-9kiTiFEBlEmsNkUJagAmzq1zI64RAasNivbO2uFpYe6lC9qcK6-BCjwy2V-p-qX-UqdvjCJO-y6Kjm_bpmRNwr_q277Vc-GKwcIqG_" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Then fill in the credentials they have asked for:</p>
<p><img src="https://lh3.googleusercontent.com/uMKaffa_5TJDMRHXl8WUCsUc3MxcyAAlwVbkCVpkbQ8c21qfV_8U9c2toKfJ-WcLj387vgJhTN54xq8MoCJO82cO68eAePTmUd7RqinyYG4659h8LazgueEWlrhEZEV0EbcO-psH" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After this, you will be directed to the developer dashboard. Click on the new project.</p>
<p><img src="https://lh6.googleusercontent.com/_FQN1PymEdAKDYwB0YR7MeUL6Ab6nPyLUkCb40SBg6jZNZj7vnxLnSRVu24NALBfbanpdF4qxze9p9xba8CRZWfTtCjp6PmNv7o12fUip3pLYAvHKqq16-d3bO7_897Df_mUQ_l4" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You will be asked to accept all the terms written there. Read them if you want or else just check all of them and click the button at the end to proceed.</p>
<p><img src="https://lh5.googleusercontent.com/IcLYr5HycXD28nEgtLF4_6Tj6Waa9XAU5B1GHf1Z-5Mrmils4seAa4gvY4kearxFkJhe0hv7p3IFau9iQdbF8a8YGVVZ-TF56y8P5T68YPWZ8H1A-ipAiVs6tONFl2kYYojQNSWa" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Next, a modal form will appear as shown below in which you have to write the application information like name and description.</p>
<p>Then click Create Application.</p>
<p><img src="https://lh3.googleusercontent.com/1Av2BfGSaXi0S9Bib2qkcaxcgioFUGMRqveNWKyMATeJG-cHkpCKAfNh4KQP4ztvhMQ7R1jcBe4x4gRnMoSbpr0oxmczqxCscgFmALMpQDSo6Zm3CLbyZbUVx7n4BF2DO75l_qVv" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now that our application has been created, we can access the <strong>Access Key</strong> and <strong>Secret Key</strong> under the <strong>Keys section</strong>:</p>
<p><img src="https://lh5.googleusercontent.com/PWKObP8aBkr8dipYCoq5lkkRC1TYbgrZcoNbo0DeunoNsoXMMqYayleGDwCjig9iXZ4eSrq4bNgsLoQ9e5Q7ohMKw9VDoajmSmvo8sI7aZKnDV3amuVRd_7agognh90R8Fkou_cs" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Notice that at the very beginning of this page, it says <strong>Demo</strong>. This means that our application has been accepted but is still in development mode.</p>
<p>In this mode, we can only make 50 requests per hour. If we exceed this limit, our API will not work and the images will not load.</p>
<p><img src="https://lh3.googleusercontent.com/iPG7K3Wl9-HOuQbAmrnhyDq5u-tplTZJ56YbDKHMpgIJ4wANdSQPBBjN_fWMPR-89RvEvEG9yYiOWGyUCnU-Qh88EXC7z1rfJ_IvnfsHhXJ5YFVMT6GkaG8WsvT4ZHlJbU86D951" alt="Image" width="600" height="400" loading="lazy"></p>
<p>After this, head over to the documentation and select the option “<strong>Search Photos by Keyword</strong>”.</p>
<p><img src="https://lh6.googleusercontent.com/4cMwgogWv858cVvy78oWmNce-GC0rZBSpFaadMh_eO-qbJ3pVHMPL90b_dUQNonSj9-NeRxvhM9hj5JZGuViTjFESmIo5m6yRWUS-gtrEuh5TA5ugLT9PCxvgbZ-3oPdbKZ9pl_z" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Scroll down to the <strong>Response</strong> Section and copy the link as shown:</p>
<p><img src="https://lh4.googleusercontent.com/3ORXGCncj8J8CxUwTYP4tesP9F-IjFSCADrAQQ0KN4DcrlmjepMvmaudZc5PZTUfzPkFdjI9IdRnDa2JYHabqJgsPHKccboA9wiDMg3SaoV9nA554OjIzRKYOHQ_g2I_p2-uJk75" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>API endpoint</em></p>
<p>Now we have both our <strong>API key and the API endpoint</strong>. Let's proceed with our App.</p>
<h2 id="heading-how-to-use-hooks-in-our-app">How to Use Hooks in our App</h2>
<p>We will be using the useState and useEffect hooks in our app. They'll let us set the states which are required to get the value of input and search the API for data regarding that value.</p>
<p>For hooks to work, we have to define them at the very top of our app like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
</code></pre>
<h3 id="heading-how-to-set-state-using-the-usestate-hook">How to Set State Using the useState Hook</h3>
<p>As we discussed above, we'll use hooks to extract data from the API using the value searched in the input field. That value will be read by our React app using the useState hook.</p>
<p>We define states using this hook for specific purposes. In this app, we will be defining two of them: one for getting the value from the input field and the other to display results fetched from the API.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [img, setImg] = useState(<span class="hljs-string">""</span>);
<span class="hljs-keyword">const</span> [res, setRes] = useState([]);
</code></pre>
<p>There are two parameters in the above code used to define the useState hook: one of them is the state which we will use to store values, and the other is the function that we will be using to update the state values. Read more about <a target="_blank" href="https://tekolio.com/what-is-the-usestate-hook-in-react/">useState hook here</a>.</p>
<p>We have defined the first state as an empty string as it will be used to store the input from the search bar (and that is also a string).</p>
<p>The other state is initialized as an empty array because it will store the data fetched from the API and then show it in our Result Section</p>
<p>By default, we can only get up to 10 data points per API, but we can exceed that using a parameter <strong>per_page</strong> which we will see later in this tutorial.</p>
<h3 id="heading-how-to-use-the-img-state">How to use the img state</h3>
<p>The next step is to store the value of the input text field into the <strong>img</strong> state using the value attribute of the input tag. Then we add an onChange() event handler to it. This onChange() event handler will have a function that will be used to update the state using the <strong>e.target.value.</strong></p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
  <span class="hljs-attr">className</span>=<span class="hljs-string">"col-3 form-control-sm py-1 fs-4 text-capitalize border border-3 border-dark"</span>
  <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
  <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Search Anything..."</span>
  <span class="hljs-attr">value</span>=<span class="hljs-string">{img}</span>
  <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setImg(e.target.value)}
/&gt;;
</code></pre>
<h3 id="heading-how-to-make-api-requests-to-unsplash-using-the-useeffect-hook">How to Make API Requests to Unsplash using the useEffect Hook</h3>
<p>We will now use the Unsplash API and the Access key we have acquired in the above step to fetch data and display it in our app.</p>
<p>For this, we will again need a state to store the data fetched from the API which we have already defined in the above section (<strong>res</strong>, which is initialized as an empty array for this purpose only).</p>
<p>There are many methods in JavaScript we can use to fetch data from an API, but we will be using the async-await method – it's by far the simplest one.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchRequest = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetch(
    <span class="hljs-string">`https://api.unsplash.com/search/photos?page=1&amp;query=<span class="hljs-subst">${img}</span>&amp;client_id=<span class="hljs-subst">${Access_Key}</span>`</span>
  );
  <span class="hljs-keyword">const</span> dataJ = <span class="hljs-keyword">await</span> data.json();
  <span class="hljs-keyword">const</span> result = dataJ.results;
  <span class="hljs-built_in">console</span>.log(result);
  setRes(result);
};
useEffect(<span class="hljs-function">() =&gt;</span> {
  fetchRequest();
}, []);
</code></pre>
<p>Notice that we have written <code>${Access_Key}</code> – here we have to write our access key. We complete this step to secure our API key as anyone can misuse it.</p>
<p>In Unsplash, we can also apply for the production of our app, and by doing so we can go online with the images that Unsplash has to offer.</p>
<p>For this reason, everyone gets a different set of Access Keys and Security Keys. It's always best to hide these keys from others so that it doesn’t get misused and we pay the price for that.</p>
<p>In the above code, we have initially stored the data fetched from the API into the <strong>data</strong> variable which is then converted into JSON for simplicity's sake. This lets us read the data and extract the necessary values, which are stored in the <strong>dataJ</strong> variable and consoled to check if we are getting the value we need or not.</p>
<p><img src="https://lh4.googleusercontent.com/U32k-__bIyqEnF_2xPC1zT293GOGH7bY-_TVWbdzhfcSkMMMbuNC1bgExFM-HETrJJvVcFC1VzunOWtJ4hq1Gh72mmuPwv6A71V-QD0luGl42wJ6gmUlQTrtj-l4tp2Ay1FjuUP1" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>API in JSON format</em></p>
<p>And if we open any one of the above search results to see what values are there for us to extract:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"total"</span>: <span class="hljs-number">133</span>,
    <span class="hljs-attr">"total_pages"</span>: <span class="hljs-number">7</span>,
    <span class="hljs-attr">"results"</span>: [
    {
    <span class="hljs-attr">"id"</span>: <span class="hljs-string">"eOLpJytrbsQ"</span>,
    <span class="hljs-attr">"created_at"</span>: <span class="hljs-string">"2014-11-18T14:35:36-05:00"</span>,
    width: <span class="hljs-number">4000</span>,
    height: <span class="hljs-number">3000</span>,
    color: <span class="hljs-string">"#A7A2A1"</span>,
    blur_hash: <span class="hljs-string">"LaLXMa9Fx[D%~q%MtQM|kDRjtRIU"</span>,
    likes: <span class="hljs-number">286</span>,
    liked_by_user: <span class="hljs-literal">false</span>,
    description: <span class="hljs-string">"A man drinking a coffee."</span>,
    user: {
    id: <span class="hljs-string">"Ul0QVz12Goo"</span>,
    username: <span class="hljs-string">"ugmonk"</span>,
    name: <span class="hljs-string">"Jeff Sheldon"</span>,
    first_name: <span class="hljs-string">"Jeff"</span>,
    last_name: <span class="hljs-string">"Sheldon"</span>,
    instagram_username: <span class="hljs-string">"instantgrammer"</span>,
    twitter_username: <span class="hljs-string">"ugmonk"</span>,
    portfolio_url: <span class="hljs-string">"http://ugmonk.com/"</span>,
    profile_image: {
    small:
    <span class="hljs-string">"https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=faces&amp;cs=tinysrgb&amp;fit=crop&amp;h=32&amp;w=32&amp;s=7cfe3b93750cb0c93e2f7caec08b5a41"</span>,
    medium:
    <span class="hljs-string">"https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=faces&amp;cs=tinysrgb&amp;fit=crop&amp;h=64&amp;w=64&amp;s=5a9dc749c43ce5bd60870b129a40902f"</span>,
    large:
    <span class="hljs-string">"https://images.unsplash.com/profile-1441298803695-accd94000cac?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=faces&amp;cs=tinysrgb&amp;fit=crop&amp;h=128&amp;w=128&amp;s=32085a077889586df88bfbe406692202"</span>,
    },
    links: {
    self: <span class="hljs-string">"https://api.unsplash.com/users/ugmonk"</span>,
    html: <span class="hljs-string">"http://unsplash.com/@ugmonk"</span>,
    photos: <span class="hljs-string">"https://api.unsplash.com/users/ugmonk/photos"</span>,
    likes: <span class="hljs-string">"https://api.unsplash.com/users/ugmonk/likes"</span>,
    },
    },
    current_user_collections: [],
    urls: {
    raw: <span class="hljs-string">"https://images.unsplash.com/photo-1416339306562-f3d12fefd36f"</span>,
    full: <span class="hljs-string">"https://hd.unsplash.com/photo-1416339306562-f3d12fefd36f"</span>,
    regular:
    <span class="hljs-string">"https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;s=92f3e02f63678acc8416d044e189f515"</span>,
    small:
    <span class="hljs-string">"https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=400&amp;fit=max&amp;s=263af33585f9d32af39d165b000845eb"</span>,
    thumb:
    <span class="hljs-string">"https://images.unsplash.com/photo-1416339306562-f3d12fefd36f?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=200&amp;fit=max&amp;s=8aae34cf35df31a592f0bef16e6342ef"</span>,
    },
    links: {
    self: <span class="hljs-string">"https://api.unsplash.com/photos/eOLpJytrbsQ"</span>,
    html: <span class="hljs-string">"http://unsplash.com/photos/eOLpJytrbsQ"</span>,
    download: <span class="hljs-string">"http://unsplash.com/photos/eOLpJytrbsQ/download"</span>,
    },
    },
    <span class="hljs-comment">// more photos ...</span>
    ],
    },
</code></pre>
<p>It's better to use this function inside the useEffect hook as it will prevent any re-rendering of the data if we made any changes in the UI of our App. To understand useEffect in-depth, <a target="_blank" href="https://tekolio.com/explaining-useeffect-hook-in-react/">click here</a>.</p>
<p>We use the <strong>setRes</strong> function to update the value of <strong>res</strong> from an empty array to an array which will store all the fetched data in the JSON format as shown above.</p>
<p>We have already given an onClick function to the button at the beginning of our app in the input section. Now it's time to define a function for this event handler which will be triggered as soon as the Search button is clicked. This function will call the <strong>fetchRequest</strong> function which will fetch the data and show us the result in the Result section.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Submit = <span class="hljs-function">() =&gt;</span> {
  fetchRequest();
  setImg(<span class="hljs-string">""</span>);
};
</code></pre>
<h2 id="heading-how-to-display-images-in-our-app">How to Display Images in our App</h2>
<p>In the above section, we have stored the data fetched from the API into the <strong>res</strong> state which has stored them in the form of an array. To get these values from there, we have to use the map method.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-12 d-flex justify-content-evenly flex-wrap"</span>&gt;</span>
  {res.map((val) =&gt; {
    return (
      <span class="hljs-tag">&lt;&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"col-3 img-fluid img-thumbnail"</span>
          <span class="hljs-attr">src</span>=<span class="hljs-string">{val.urls.small}</span>
          <span class="hljs-attr">alt</span>=<span class="hljs-string">"val.alt_description"</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/&gt;</span>
    );
  })}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>;
</code></pre>
<p>If we go back and see the response in JSON, we will find a different kind of information: <strong>URLs</strong> which contains the path to the image. So here <strong>val.urls.small</strong> is the actual path to the image, and <strong>val.alt_description</strong> is the alt description of the picture.</p>
<p>There are different fields inside "urls" that give different data, such as:</p>
<ul>
<li><p><strong>Raw</strong>: Actual raw image that was taken by a user.</p>
</li>
<li><p><strong>Full</strong>: Raw image in .jpg format.</p>
</li>
<li><p><strong>Regular</strong>: Best for practical uses, width=1080px.</p>
</li>
<li><p><strong>Small</strong>: Perfect for slow internet speed, width=400px.</p>
</li>
<li><p><strong>Thumb</strong>: Thumbnail version of the image, width=200px.</p>
</li>
</ul>
<p>In this article, we will be using small, but there are others too as shown above that we can play with and find the appropriate one for us.</p>
<p><img src="https://lh4.googleusercontent.com/W8UFqJV3_yVh1-Ntvljzv09XXDjxgMwl9L_6ZiX9M5ZRAKAIbShkvJEF4XaN-UD_yI1c7o7K9s1rC5kTmuDGAaEfWDPTV4vYeIj8DUIWn57x7Y6buR8WLgRwP-oJNTHn9MHo-1iY" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Final Product</em></p>
<p>By default, the number of items that can be fetched at a time is 10, but this number can be increased or decreased depending upon how many images we want our app to show.</p>
<p>To do this we just have to add a parameter at the end of our API call (<strong>per_page</strong>) as shown in the code, and put it equal to the number of images we want to show.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> fetchRequest = <span class="hljs-keyword">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetch(
    <span class="hljs-string">`https://api.unsplash.com/search/photos?page=1&amp;query=<span class="hljs-subst">${img}</span>&amp;client_id=<span class="hljs-subst">${Access_Key}</span>&amp;per_page=20`</span>
  );
  <span class="hljs-keyword">const</span> dataJ = <span class="hljs-keyword">await</span> data.json();
  <span class="hljs-keyword">const</span> result = dataJ.results;
  <span class="hljs-built_in">console</span>.log(result);
  setRes(result);
};
</code></pre>
<p>There are many more parameters that Unsplash has to offer. Below is a list of a few of them:</p>
<p><img src="https://lh5.googleusercontent.com/zFYDDwnZ52Cx7NUoKL31GiT_87ZeQQ0B9LZeMGShHsXUmu94FbvZHxYJnEOymSoxq-gy2RMItMppHP8cgTmJSB34djJf02Ae0Ji2nXtPbpB91muUg6D3gYrwq69fvrcAu8YVWbqv" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>parameters of Unsplash API</em></p>
<h2 id="heading-how-to-handle-errors">How to Handle Errors</h2>
<p>If we do a quick search now on, say, flags, we will get our images. But there are still some issues that need to be fixed. One of them is the error we are receiving in the console.</p>
<p><img src="https://lh4.googleusercontent.com/nNglt_EjKldYnndufDLUOsK1yxvJmywsrjK3XOmm11jhEs3EfuIudjqahEvzJRt9JBtypzpWZDsE3QBgATN9ry7vD5vPrK42zeux23YBcVQ4NzvWcYNsL1Ha6X6YP1QoK7zZRCSm" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Error in Console</em></p>
<p>To fix this, pass a unique key to every child using the id of the image. This key prop explicitly tells React the identity of each child in a list. This also prevents children from losing state between renders.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-12 d-flex justify-content-evenly flex-wrap"</span>&gt;</span>
  {res.map((val) =&gt; {
    return (
      <span class="hljs-tag">&lt;&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
          <span class="hljs-attr">key</span>=<span class="hljs-string">{val.id}</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"col-3 img-fluid img-thumbnail"</span>
          <span class="hljs-attr">src</span>=<span class="hljs-string">{val.urls.small}</span>
          <span class="hljs-attr">alt</span>=<span class="hljs-string">"val.alt_description"</span>
        /&gt;</span>
      <span class="hljs-tag">&lt;/&gt;</span>
    );
  })}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>;
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we have developed a Photo Search app in React using the Unsplash API. While building our app, we discussed many things like how to use React Hooks to get the data from an API and use it to display images in our App.</p>
<p>There is much more you can do with this application to extend it. For example, we could add a Random button to display random images, create a checkbox to toggle between searching for photos or the users that posted them according to the user’s preference, add an <a target="_blank" href="https://www.npmjs.com/package/react-infinite-scroll-component">infinite scroll</a> to display more images, and more.</p>
<p>You can go through some of my other beginner-friendly, project-based articles here:</p>
<ol>
<li><p><a target="_blank" href="https://tekolio.com/how-to-make-a-table-in-react-with-hooks/">How to Make a Table in React using Hooks with Multiple Features</a></p>
</li>
<li><p><a target="_blank" href="https://tekolio.com/how-i-made-my-portfolio-in-react/">How I made my Portfolio in React</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/how-to-make-a-filter-component-in-react/">How to Make a Filter Component in React</a></p>
</li>
</ol>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ <img> HTML – Image Tag Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ In HTML, you use the <img> tag to add images to websites. It is an inline and empty element, which means that it doesn't start on a new line and doesn't take a closing tag (unlike the paragraph (<p>) tag, for instance). The <img> tag takes several at... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/img-html-image-tag-tutorial/</link>
                <guid isPermaLink="false">66adf1837550d4f37c2019b5</guid>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kolade Chris ]]>
                </dc:creator>
                <pubDate>Wed, 11 Aug 2021 15:28:58 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/08/imgTag.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In HTML, you use the <code>&lt;img&gt;</code> tag to add images to websites. It is an inline and empty element, which means that it doesn't start on a new line and doesn't take a closing tag (unlike the paragraph (<code>&lt;p&gt;</code>) tag, for instance).</p>
<p>The <code>&lt;img&gt;</code> tag takes several attributes, of which <code>src</code>, <code>height</code>, <code>width</code>, and <code>alt</code> are the most important. </p>
<p>Knowing the ins and outs along with some best practices of the <code>&lt;img&gt;</code> tag is crucial because images can negatively affect your site's load time and SEO. </p>
<p>So in this tutorial, we will take a look at how to add images to websites using the <code>&lt;img&gt;</code> tag, how to use its attributes, some best practices, and modern approaches to using <code>&lt;img&gt;</code>.</p>
<h2 id="heading-basic-html-tag-syntax">Basic HTML <code>&lt;img&gt;</code> Tag Syntax</h2>
<p>Here's the basic syntax for adding an <code>&lt;img&gt;</code> tag to your HTML:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> 
    <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/images/ring-tailed-lemurs.webp"</span> 
    <span class="hljs-attr">alt</span>=<span class="hljs-string">"A Group of Ring-tailed Lemurs"</span> 
/&gt;</span>
</code></pre>
<p>Now let's talk about its attributes and how they work.</p>
<h2 id="heading-html-tag-attributes">HTML <code>&lt;img&gt;</code> Tag Attributes</h2>
<h3 id="heading-the-src-attribute">The <code>src</code> Attribute</h3>
<p>The <code>src</code> attribute signifies the image source. Without it, the tag itself wouldn't be functional in the real world. </p>
<p>It indicates to the browser where to find the image. So it takes a relative path if the image is hosted locally, or an absolute URL if the image is hosted online. </p>
<h3 id="heading-the-alt-attribute">The <code>alt</code> Attribute</h3>
<p>The alt attribute specifies an alternative text for the image. This could be the text that shows during a network failure, for example. Or it could display something when the image source is wrongly specified, so users know what the image is about.  </p>
<p>In the code snippet below, the image source is wrongly specified, showing you the role that the <code>alt</code> attribute plays:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
     <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/images/ring-tailed-lemur.webp"</span>
     <span class="hljs-attr">alt</span>=<span class="hljs-string">"A Group of Ring-tailed Lemurs"</span>
/&gt;</span>
</code></pre>
<p>This is the CSS that centers the image horizontally and vertically:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
   <span class="hljs-attribute">display</span>: flex;
   <span class="hljs-attribute">align-items</span>: center;
   <span class="hljs-attribute">justify-content</span>: center;
   <span class="hljs-attribute">flex-direction</span>: column;
   <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  }
</code></pre>
<p>And it looks like this: 
<img src="https://www.freecodecamp.org/news/content/images/2021/08/alt-text-1.png" alt="alt-text-1" width="600" height="400" loading="lazy"></p>
<p>The alt attribute is very important for 2 other reasons:</p>
<ul>
<li>SEO: it indicates to web crawlers what the image is about</li>
<li>Accessibility: it helps screen readers know what the image is about so they can report that to visually impaired people. In addition, it lets users with low bandwidth know what the image is about.</li>
</ul>
<h3 id="heading-the-width-and-height-attributes">The <code>width</code> and <code>height</code> Attributes</h3>
<p>You can use these attributes to specify a certain width and height for your images. With these attributes, you can resize the image down or up. </p>
<p>Ideally, though, you shouldn't resize an image with these attributes. We'll touch on this more under best practices.</p>
<h2 id="heading-html-tag-best-practices">HTML <code>&lt;img&gt;</code> Tag Best Practices</h2>
<h3 id="heading-do-not-resize-an-image-with-the-width-and-height-attributes">Do not resize an image with the width and height attributes.</h3>
<p>This is a bad practice because it can make the image appear distorted and can affect the quality. </p>
<p>Instead, you can optimize the image to your desired dimensions with photo editing software such as Photoshop. </p>
<p>In the code snippet below, I specify a width and height for the image – a bad practice:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
      <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/images/ring-tailed-lemurs.webp"</span>
      <span class="hljs-attr">height</span>=<span class="hljs-string">"440px"</span>
      <span class="hljs-attr">width</span>=<span class="hljs-string">"440px"</span>
      <span class="hljs-attr">alt</span>=<span class="hljs-string">"A Group of Ring-tailed Lemurs"</span>
/&gt;</span>
</code></pre>
<p>The image looks like this:
<img src="https://www.freecodecamp.org/news/content/images/2021/08/wrong-width-height-usage-1.png" alt="wrong-width-height-usage-1" width="600" height="400" loading="lazy"></p>
<p>Without using the width and height attributes, the image looks like this:
<img src="https://www.freecodecamp.org/news/content/images/2021/08/no-width-height-1.png" alt="no-width-height-1" width="600" height="400" loading="lazy"></p>
<p>Looks better? Yes!</p>
<h3 id="heading-name-your-images-appropriately">Name Your Images Appropriately</h3>
<p>Naming images appropriately can help search engines understand what the image is about. For example, name an image <code>ring-tailed-lemurs.webp</code> instead of <code>photo-1580855733764-084b90737008.webp</code>. The latter is not enough for search engine optimization (SEO).</p>
<h3 id="heading-reduce-image-file-size">Reduce Image File Size</h3>
<p>The image's file size is crucial when it comes to page speed. A smaller image size (that preserves the image's quality) reduces load time while larger images take forever to load. </p>
<p>There are several tools and various software that can help you do this. Some examples are imageOptim, jStrip, and PNGGauntet. And if you're concerned about SEO, you'll want to look into these – as page speed is an important ranking factor.</p>
<h3 id="heading-host-images-with-a-cdn">Host Images with a CDN</h3>
<p>Imagine if a website is hosted in the United States but a user in Africa wants to accessed it. Assets such as images and icons would have to travel from The States to Africa, which in turn slows download time.</p>
<p>Using a CDN (Content Delivery Network) will allow the website's images to be cached across several locations around the world. The CDN can then serve them from locations closest to the user, improving load time and providing a better user experience. </p>
<p>Cloudflare is a popular CDN that a lot of developers use to host their images.</p>
<h3 id="heading-use-descriptive-alternative-text">Use Descriptive Alternative Text</h3>
<p>Using descriptive alternative text helps search engines understand what the image is about. But it doesn't end there – the alt text must also be relevant to the image. </p>
<p>For example, use this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
   <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/images/ring-tailed-lemurs.webp"</span>
   <span class="hljs-attr">alt</span>=<span class="hljs-string">"A Group of Ring-tailed Lemurs"</span>
/&gt;</span>
</code></pre>
<p>Insead of this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/images/ring-tailed-lemurs.webp"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Lemurs"</span> /&gt;</span>
</code></pre>
<h3 id="heading-use-the-title-attribute-to-show-tooltips">Use the <code>title</code> Attribute to Show Tooltips</h3>
<p>Just like the <code>alt</code> attribute, you can use the <code>title</code> attribute to show additional information about the image. Browsers display this as a tooltip when the user hovers over the image.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
    <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/images/ring-tailed-lemurs.webp"</span>
    <span class="hljs-attr">alt</span>=<span class="hljs-string">"A Group of Ring-tailed Lemurs"</span>
    <span class="hljs-attr">title</span>=<span class="hljs-string">"Ring-tailed lemurs are led by females"</span>
/&gt;</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/tooltip-1.png" alt="tooltip-1" width="600" height="400" loading="lazy"></p>
<h2 id="heading-tag-modern-approaches"><code>&lt;img&gt;</code> Tag Modern Approaches</h2>
<p>There are various ways you can use the <code>&lt;img&gt;</code> tag that are a bit more up to date and modern. Let's look at some of them now.</p>
<h3 id="heading-lazy-load-images">Lazy Load Images</h3>
<p>Lazy loading is a newish "load what is needed" concept. With lazy loading, the image is loaded only when the user scrolls to its viewport. </p>
<p>This is in contrast to eager loading, which loads every image immediately after the page is rendered by the browser. </p>
<p>To apply lazy loading, add the loading attribute to the <code>&lt;img&gt;</code> tag and set the value to “lazy”.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
      <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/images/ring-tailed-lemurs.webp"</span>
      <span class="hljs-attr">alt</span>=<span class="hljs-string">"A Group of Ring-tailed Lemurs"</span>
      <span class="hljs-attr">title</span>=<span class="hljs-string">"Ring-tailed lemurs are led by females"</span>
      <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>
/&gt;</span>
</code></pre>
<p>Images are often quite high quality and large these days, but this can negatively impact user experience and SEO – hence the introduction of lazy loading. </p>
<h3 id="heading-use-the-and-tags">Use the <code>&lt;figure&gt;</code> and <code>&lt;figcaption&gt;</code> Tags</h3>
<p>Often, you might need to specify to the user the caption of an image. A lot of developers do this by placing a <code>&lt;p&gt;</code> tag right after the <code>&lt;img&gt;</code>. </p>
<p>This might not be wrong, but it defies best practices and does not associate the caption with the image, so search engines won’t understand what it is. </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span>
      <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/images/ring-tailed-lemurs.webp"</span>
      <span class="hljs-attr">alt</span>=<span class="hljs-string">"A Group of Ring-tailed Lemurs"</span>
      <span class="hljs-attr">title</span>=<span class="hljs-string">"Ring-tailed lemurs are led by females"</span>
      <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>
/&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Ring-tailed lemurs are social animals<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/wrong-captioning-1.png" alt="wrong-captioning-1" width="600" height="400" loading="lazy"></p>
<p>Its is clear that there is no association between the image and the caption in the above example.</p>
<p>HTML5 introduced the <code>&lt;figure&gt;</code> and <code>&lt;figcaption&gt;</code> elements to help with this. You wrap the <code>&lt;img&gt;</code> tag inside a <code>&lt;figure&gt;</code> element, and you specify a caption within the <code>&lt;figcaption&gt;</code> element. </p>
<p>This helps search engines associate the caption with the image, leading to better performance and SEO. </p>
<p>The snippets of code below and the screenshots show you an image with and without the <code>&lt;figure&gt;</code> and <code>&lt;figcaption&gt;</code> elements:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">figure</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">img</span>
     <span class="hljs-attr">src</span>=<span class="hljs-string">"assets/images/ring-tailed-lemurs.webp"</span>
     <span class="hljs-attr">alt</span>=<span class="hljs-string">"A Group of Ring-tailed Lemurs"</span>
     <span class="hljs-attr">title</span>=<span class="hljs-string">"Ring-tailed lemurs are led by females"</span>
     <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>
   /&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">figcaption</span>&gt;</span>Ring-tailed lemures are social animals<span class="hljs-tag">&lt;/<span class="hljs-name">figcaption</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span>
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/right-captioning.png" alt="right-captioning" width="600" height="400" loading="lazy"></p>
<p>You can see now that the image and the caption are beautifully associated.</p>
<h3 id="heading-use-the-webp-image-format">Use the .webP Image Format</h3>
<p>.webP is an image format created by Google. According to the creator, it's an image format lower in size than its counterparts - JPG, JPEG, PNG, but with the same quality. </p>
<p>This format has been getting more and more widely accepted and is considered the nextgen image format for the web.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I hope this article helps you understand how the <code>&lt;img&gt;</code> tag works in HTML so you can use it properly in your projects. If you do so, it'll help improve your user experience and SEO.</p>
<p>Thanks a lot for reading, and keep coding.   </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Reverse Image Search on Your Phone or Desktop – Free Image Lookup Tools ]]>
                </title>
                <description>
                    <![CDATA[ By Adam Naor Over the past two years, mobile searches for “image search” have grown by over 60% according to Google.  That is because image search allows users to visualize any given keyword from thousands of images from around the internet.  Perhaps... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-reverse-image-search-on-your-phone-or-desktop/</link>
                <guid isPermaLink="false">66d45d6ab3016bf139028d21</guid>
                
                    <category>
                        <![CDATA[ Google ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Photography ]]>
                    </category>
                
                    <category>
                        <![CDATA[ search ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 18 Dec 2020 22:01:44 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5fdd0892e6787e09839406ee.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Adam Naor</p>
<p>Over the past two years, mobile searches for “image search” have grown by over 60% according to Google. </p>
<p>That is because image search allows users to visualize any given keyword from thousands of images from around the internet. </p>
<p>Perhaps you have seen images from online photo editors, a landscape painting, or a cool product release that catches your eye and you want to learn more. </p>
<p>Image search is the answer.</p>
<p>Reverse image search allows you to do work backwards and gain new insights from the image itself. I will detail how reverse image search works across multiple platforms so you will be well prepared to harness this technology going forward.</p>
<h2 id="heading-what-is-a-reverse-image-search">What Is a Reverse Image Search?</h2>
<p>This technology enables you to Google the origins of any photograph, artwork, graph, or photo. By reverse image searching, you can find the image on all the pages on which it was featured - even if the image is a different aspect ratio or file size. </p>
<p>You can also find links to image search results of similar images. In addition, image search offers your query possible related searches.</p>
<p>You can start a reverse search image on your phone or desktop through Google, Bing, or any similar tool. I will walk you through the exact steps now.</p>
<h2 id="heading-how-to-reverse-image-search-on-desktop">How to Reverse Image Search on Desktop</h2>
<p>You have a few options for image search depending on your preferences, operating system, and device.</p>
<h3 id="heading-reverse-image-search-with-a-desktop-browser"><strong>Reverse Image Search With a Desktop Browser</strong></h3>
<p>To perform this version of an image search, follow these steps:</p>
<ol>
<li>Start by going to <a target="_blank" href="https://images.google.com/">images.google.com</a>.</li>
<li><p>Next, click on the camera icon which will allow you to choose from two options. </p>
</li>
<li><p>First, you can paste the URL of an image from another page.</p>
</li>
<li>The second option is to upload the image itself.   </li>
</ol>
<p><img src="https://lh4.googleusercontent.com/p0Npw4idkZLuSp1Jkk2u1K6_Fn9Z13ZmVGzqCkYKS4rKQIHCzjcDTb02YutU6Db5u8oMpXu_eFILD8an-r_sqekvOyQsuKsIOiPfDTIRDV5XQKpzuhSEitJPZGHQmEJn_J0HfZlH" alt="Image" width="1366" height="768" loading="lazy"></p>
<ol start="3">
<li>Then, simply click ‘enter’ on your keyword or the ‘search by image’ button to get results.</li>
</ol>
<h3 id="heading-reverse-image-search-with-google-chrome-desktop-browser"><strong>Reverse Image Search with Google Chrome Desktop Browser</strong></h3>
<p>If you are already using Google Chrome, then you can shortcut the process significantly. When stumbling upon an image on any page online on Chrome, you can carry out a reverse image search by following these steps:</p>
<ol>
<li>Right-click on the image you would like to find out more about.</li>
<li>Choose ‘Search Google for Image’ from the drop-down menu.  </li>
</ol>
<p><img src="https://lh4.googleusercontent.com/HGRNCk9ktfpPCocQ2FMud29h-69hHnCuiBLvcJxQ-TxOxV9SWN0BcKFw73NP9WR26iNwU_R_HwMXB933XELhiUcDKzm4vtX0QDz3OoC9R5gnfGuuSFIjddmYZ-fQPFXx51FUQGvO" alt="Image" width="1366" height="768" loading="lazy"></p>
<p>This straightforward method will display your search results instantly.</p>
<p><img src="https://lh5.googleusercontent.com/V9YXAyoiN1DdkP6k_-3UNlpgEP3sb-Jxm5ebYMEBeQkAM1GrHEU4BQX4SLbOHEgEv1Cssrk5wBgCnippFBWq0kR-pUNcKMm2_OpDGHfAxcZM0vVcbbKgQNcrDBFO_Jjd5FoDkY4a" alt="Image" width="1366" height="768" loading="lazy"></p>
<p>Image search is very powerful. Here is one example. I recently saw this photo and was intrigued. I wanted to learn more. </p>
<p>So I uploaded it to Google and was told that the photo featured Sineenat Wongvajirapakdi, a Thai nurse, army officer, and member of the Thai royal court. </p>
<p>Without image search I never could have found that information out.</p>
<p><img src="https://lh3.googleusercontent.com/b0JXALnXEM7ou_x2n9uBlnAvY8TNTsIiPc5ejnuio3NA_Acch7csdP6MfT2qAJXDyvpaeE2T3eAhKycdI7mvMX9eZomaQzkZSI2rqeoiuNwfjF30qsgYKeeOELd-IuBqKDF3WWdo" alt="Image" width="1172" height="782" loading="lazy"></p>
<h3 id="heading-reverse-image-search-using-microsoft-bing"><strong>Reverse Image Search Using Microsoft Bing</strong></h3>
<p>Since Bing has over 10% market share worldwide, it is safe to say there is a whole audience of builders and developers using it. So I wanted to include steps for this search engine too.</p>
<p>Bing’s visual search is slightly different from Google’s. This is because it detects shopping intents, for example, and provides search results that contain other similar products with their pricing information.</p>
<p>Here is how to conduct a reverse image search on Microsoft Bing:</p>
<ol>
<li>Open Microsoft Bing through a browser or the application.</li>
</ol>
<p><img src="https://lh3.googleusercontent.com/E40ZZFWuXC8TURcl0saNbPCjxqpgIZD-qOOPNp3L4nIQX6cN7hAgarrhIhgSsvTPVm0_3WuqrfZmPkQ91k_IA8GjRFlfoVYdd2_SJZGNtxOLlwevlDRHR_INzRUJBkdYwkqi7Hmo" alt="Image" width="1366" height="768" loading="lazy"></p>
<ol start="2">
<li>Click the camera-shaped icon in the search bar.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/vQn9-9OW_DzK6aOBciFr27lJ04ZhBkdssWAxMitBIEETnpY_eV4TSemah5sl0Hj-OxI4myCkTeYHYXm1O845C3eL9cr2LWvaHube3e0kwkFLWFioVRE-gwWW3QPGiMEOpkLwY_wk" alt="Image" width="1366" height="768" loading="lazy"></p>
<ol start="3">
<li><p>The pop-up menu will give you four options to search with a picture instead of text. Let’s explore the options:</p>
</li>
<li><p>First, drag one or more images to the search box from your computer.</p>
</li>
<li>Second, browse your computer for the image you would like to search for.</li>
<li>You can also paste the URL of the image from an online page that you were previously browsing.</li>
<li>The final option is to take a photo and search for more information on it. Whether it is a product or a location, you can find out more.</li>
</ol>
<p>Finally, browse the visual search results at your leisure. </p>
<p><img src="https://lh6.googleusercontent.com/44mmbBwM1nJt46O5ZMjwM46QgfFwIskb4fsHGH2nra3zgDjbHv2LlIE4TlqH70EnAGaQjpuDQiTRUXpN8jyVz009z7DEedrf1HzkYGMyZcXvmmrGUze1_DJwF_XN6s9IBylWlyui" alt="Image" width="1366" height="768" loading="lazy"></p>
<h2 id="heading-how-to-reverse-image-search-on-your-phone">How to Reverse Image Search on Your Phone</h2>
<p>It can be slightly more challenging to do a reverse image search on your phone. You have multiple options, but they require a few more steps. Let’s walk through them together.</p>
<h3 id="heading-reverse-image-search-using-the-google-chrome-app"><strong>Reverse Image Search Using the Google Chrome App</strong></h3>
<p>Unfortunately, the Google Chrome application itself does not support reverse image search on Mobile. But you can still do it through a smart workaround, which I will share with you. Here is how to do it: </p>
<ol>
<li>Open Google Chrome and type in ‘<a target="_blank" href="https://images.google.com/">images.google.com</a>’.</li>
<li>Tap the three-dots menu on the top right of your screen.</li>
<li>Pick ‘Desktop Site’ from the drop-down menu.</li>
<li>Click on the camera-shaped button in the search bar and insert your image in either method that suits you.</li>
</ol>
<h3 id="heading-reverse-image-search-using-any-browser-app"><strong>Reverse Image Search Using Any Browser App</strong></h3>
<p>Have you found an image that you would like to know more about on the spot while you were browsing? How do you reverse image search that exact photo? Here are the steps:</p>
<ol>
<li>Keep a long press on the image you would like to search.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/Bam58BBAf7yvzo3I-l1VdKRJ1tfV6OWsEpP9ioaINpdixkqK5SzoTP8Z1Y0MxSBUuleMBhSuXm_61bVDAAN6Gzu17EQ7OpWPYOFg6n-BJPYAd5C4vSFthxqckzVJMY4qub1IthMT" alt="Image" width="1065" height="1600" loading="lazy"></p>
<ol start="2">
<li>From the drop-down menu, select ‘Search Google for this image’.</li>
</ol>
<p>There is nothing left to do but browse the search results for more information.</p>
<h3 id="heading-reverse-image-search-using-the-google-lens-app"><strong>Reverse Image Search Using the Google Lens App</strong></h3>
<p>Google Lens is an application that allows users to search by image in multiple ways. From scanning and translating texts to searching for fashion items in different online stores, this application fulfills any search by image scenario you can think of. </p>
<p>Let’s see how it works:</p>
<ol>
<li>Download and launch the Google Lens application.</li>
<li><p>Choose the action you need for the image you will be searching for. Here are your options:</p>
</li>
<li><p>Translate: this feature allows you to translate any text on any image immediately through auto-detect. You can choose the language the text is in or the language you would like it to translate to.</p>
</li>
<li>Text: this instant copier can copy any text on your image for you to paste anywhere you would like.</li>
</ol>
<p><img src="https://lh5.googleusercontent.com/Mtus4bkyOzzFQrfL8k3H_AMsASQ9Q3a4oyfqO5mGxfx7F_purJeNfViCvx4-xDCUwbXCqijORDjH93aLC6bkfCk1FdrRqrfzmPDNu6clv_falNCqmEfwbTFe6BmybsDjcynJdBGY" alt="Image" width="900" height="1600" loading="lazy"></p>
<ul>
<li>Search: this button pretty much does the standard Google image search on whatever item or photo you are looking for.</li>
</ul>
<p><img src="https://lh5.googleusercontent.com/eMUjsYvUHhwksN_AnIFlMH_jNFL2pyIDD7IYMOyekvu7uv4VvTAQ0SpD-zYtjVM6imU-Glw_AnOWSO-LqohQmhgDZVNCKNGLZJkGDbucN0wIDHtfYAmKh4jP1knwtQgJyFNzUYMF" alt="Image" width="900" height="1600" loading="lazy"></p>
<p><img src="https://lh6.googleusercontent.com/mQ6PPs5nMvB0EuyfmamBr34rgt45ZZ3a9HsIcx7V8DkIO3z-WCxRbIVuQfBFGndUQyY__PYN3mtV2yXsPtzPI7Kcm3pdoIxx1PeJZ6O6rcJhxHGZGjqGQEmg1e37RcE6s3wYWuNa" alt="Image" width="900" height="1600" loading="lazy"></p>
<ul>
<li>Shopping: this allows you to know more about a certain product in the image or even through its barcode.</li>
<li>Dining: this fun feature lets you find out more about a dish or translate a restaurant’s menu.</li>
</ul>
<p>You will have two options for uploading the image:</p>
<ul>
<li>Take a photo of something in front of you that you would like to search for on the spot.</li>
<li>Or upload a photo from your phone that includes what you would like to know more about.</li>
</ul>
<h3 id="heading-reverse-image-search-using-pinterest-lens"><strong>Reverse Image Search Using Pinterest Lens</strong></h3>
<p>Pinterest is one of the most popular applications in the world. Its search by image feature under the name ‘Pinterest Lens’ has revolutionized the digital shopping world. </p>
<p>By following these steps, you can find, save, or shop for any item in an image you love:</p>
<ol>
<li>Launch the Pinterest app on your phone.</li>
<li>Click on the search button in the menu at the bottom of your screen.  </li>
</ol>
<p><img src="https://lh5.googleusercontent.com/caqyzpq6GqDFkDCdehbjiXsplmkdWinWw0lPZ7yxaDvkCJ0IulXGVeKF403EDPXwSCDXFhE2Ac6x5xJ3uM31gQeY9dgnHpsBfSlaQ6W6qu4UOBy2mKydUYrDuJZnOT39vHjxRwrv" alt="Image" width="900" height="1600" loading="lazy"></p>
<ol start="3">
<li><p>Tap the camera-shaped button in the search bar at the top of the screen.</p>
</li>
<li><p>You will have two options to pick your image:</p>
</li>
<li><p>Take a photo with your mobile’s camera and begin your search.</p>
</li>
<li>Or upload an image from your gallery.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/Tzr6cCYEpdKAcnKWtGHRQIr9Rd_I-g0xnDlmX6en5ST6E7afxbVeMAimiOSSHLSaqtK4oOqO0HPiPQ3yfMwlRqcGt9B7b0rTNrRt38Pwl6UyjvhZu8XaHCX2woQhWtO6NDnjTmzG" alt="Image" width="900" height="1600" loading="lazy"></p>
<h2 id="heading-bringing-it-all-together">Bringing It All Together</h2>
<p>This article has covered some fun, easy, and powerful tips for perfecting a reverse image search on your phone or desktop. </p>
<p>Reverse image search is enriching for learning, exploration, and the curious builder.</p>
<p>Not only do consumers benefit from this technology, but companies do too as they build out and scale their products. If you think reverse image search is just for fun and consumers, let me help you see the commercial potential.</p>
<p>Customer service software is increasingly using reverse image search to help agents resolve customer support tickets. The same is true for technology agencies as they look for products to purchase to help their clients. </p>
<p>A friend of mine built a company that made visual recognition software for maintenance and repair supplies. How did that company end up? Well, it was acquired by Google.  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use SVG Images in CSS and HTML – A Tutorial for Beginners ]]>
                </title>
                <description>
                    <![CDATA[ By Edidiong Asikpo SVG stands for Scalable Vector Graphics. It is a unique type of image format for vector-based graphics written in Extensible Markup Language (XML). In this tutorial, I will explain why you'd want to use SVG images and how you can u... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/use-svg-images-in-css-html/</link>
                <guid isPermaLink="false">66d45e48052ad259f07e4aa5</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image optimization  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SVG ]]>
                    </category>
                
                    <category>
                        <![CDATA[ xml ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 16 Nov 2020 22:44:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/Screen-Shot-2020-11-15-at-3.59.07-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Edidiong Asikpo</p>
<p>SVG stands for Scalable Vector Graphics. It is a unique type of image format for vector-based graphics written in Extensible Markup Language (XML).</p>
<p>In this tutorial, I will explain why you'd want to use SVG images and how you can use them in CSS and HTML.</p>
<h2 id="heading-why-should-you-use-svg-images">Why Should You Use SVG Images?</h2>
<p>There are a number of reasons to use SVG images, some of which are:</p>
<ul>
<li><p>SVG images do not lose their quality when zoomed or resized.</p>
</li>
<li><p>They can be created and edited with an IDE or text editor.</p>
</li>
<li><p>They are accessible and animatable.</p>
</li>
<li><p>They have a small file size and are highly scalable.</p>
</li>
<li><p>And they can be searched, indexed, scripted, and compressed.</p>
</li>
</ul>
<p>Now let's see how you can actually work with SVG images.</p>
<h2 id="heading-how-to-download-the-svg-image-used-in-this-tutorial">How to Download the SVG Image Used in This Tutorial</h2>
<p>If you want to work with the SVG image I've used in this tutorial, follow the steps (and diagram) below to download it.</p>
<ul>
<li><p>Go to <a target="_blank" href="https://undraw.co">unDraw</a>.</p>
</li>
<li><p>Change the background color to yellow.</p>
</li>
<li><p>In the search box, search for the word <strong>happy</strong>.</p>
</li>
</ul>
<p><img src="https://i.imgur.com/ncSY7Rn.png" alt="unDraw's Homepage" width="1836" height="888" loading="lazy"></p>
<ul>
<li><p>Click on the image named <strong>Happy news</strong>.</p>
</li>
<li><p>On the pop-up window, click on the <strong>Download SVG to your projects</strong> button.</p>
</li>
</ul>
<p><img src="https://i.imgur.com/qGrT73n.png" alt="Download the SVG file" width="1336" height="581" loading="lazy"></p>
<p>If you followed the steps above correctly, the SVG image should be on your computer now.</p>
<p><img src="https://i.imgur.com/3uCGy6B.png" alt="Image" width="1003" height="183" loading="lazy"></p>
<p>Now, open the SVG image in your favorite IDE or text editor. Rename it to <strong>happy.svg</strong> or whatever name you prefer.</p>
<h2 id="heading-how-to-use-svg-images-in-css-and-html">How to Use SVG Images in CSS and HTML</h2>
<p>There are several different ways to use SVG images in CSS and HTML. We will explore six different methods in this tutorial.</p>
<h3 id="heading-1-how-to-use-an-svg-as-an">1. How to use an SVG as an <code>&lt;img&gt;</code></h3>
<p>This method is the simplest way to add SVG images to a webpage. To use this method, add the <code>&lt;img&gt;</code> element to your HTML document and reference it in the <code>src</code> attribute, like this:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span> = <span class="hljs-string">"happy.svg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"My Happy SVG"</span>/&gt;</span>
</code></pre>
<p>Assuming you downloaded the SVG image from unDraw and renamed it to <strong>happy.svg</strong>, you can go ahead and add the code snippet above into your HTML document.</p>
<p>If you did everything correctly, your webpage should look exactly like the demo below. 👀</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-mppxs?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<p>When you add an SVG image using the <code>&lt;img&gt;</code> tag without specifying the size, it assumes the size of the original SVG file.</p>
<p>For instance, in the demo above, I didn't modify the size of the SVG image, so it assumed its original size (which was a width of <code>915.11162px</code> and a height of <code>600.53015px</code> ).</p>
<p><strong>Note:</strong> to change the original size, you have to specify the <code>width</code> and <code>height</code> with CSS as you can see in the demo below. You can also update the original <code>width</code> and <code>height</code> directly.</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-1-ey5me?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<p>Even though we can change the size of SVG images added via the <code>&lt;img&gt;</code> tag, there are still some restrictions if you want to make major style changes to the SVG image.</p>
<h3 id="heading-2-how-to-use-svg-as-a-css-background-image">2. How to use SVG as a CSS <code>background-image</code></h3>
<p>This is similar to adding SVG to an HTML document using the <code>&lt;img&gt;</code> tag. But this time we do it with CSS instead of HTML as you can see in the code snippet below.</p>
<pre><code class="lang-bash">body {
  background-image: url(happy.svg);
}
</code></pre>
<p>When you use an SVG as a CSS background image, it has similar limitations to using <code>&lt;img&gt;</code>. Still, it allows a bit more customization.</p>
<p>Check out the demo below and feel free to make modifications to it using CSS.</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-2-ftn6n?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<h3 id="heading-3-how-to-use-inline-svg-images">3. How to use inline SVG images</h3>
<p>SVG images can be written directly into the HTML document using the<code>&lt;svg&gt; &lt;/svg&gt;</code> tag.</p>
<p>To do this, open the SVG image in VS code or your preferred IDE, copy the code, and paste it inside the <code>&lt;body&gt;</code> element in your HTML document.</p>
<pre><code class="lang-bash">&lt;body&gt;
 // Paste the SVG code here.
&lt;/body&gt;
</code></pre>
<p>If you did everything correctly, your webpage should look exactly like the demo below.</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-3-zunkd?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<p>When you use SVG inline in the HTML document, it reduces load time because it serves as an HTTP request.</p>
<p>Using this method lets you perform more customization as opposed to using either the <code>&lt;img&gt;</code> or <code>background-image</code> methods.</p>
<h3 id="heading-4-how-to-use-an-svg-as-an">4. How to use an SVG as an <code>&lt;object&gt;</code></h3>
<p>You can also use an HTML <code>&lt;object&gt;</code> element to add SVG images to a webpage using the code syntax below:</p>
<pre><code class="lang-bash">&lt;object data=<span class="hljs-string">"happy.svg"</span> width=<span class="hljs-string">"300"</span> height=<span class="hljs-string">"300"</span>&gt; &lt;/object&gt;
</code></pre>
<p>You use the <code>data</code> attribute to specify the URL of the resource that you'll use by the object, which is the SVG image in our case.</p>
<p>You use the <code>width</code> and <code>height</code> to specify the size of the SVG image.</p>
<p>Again, below is a demo for you to explore. 😃</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-4-3ge0n?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<p>Using the <code>&lt;object&gt;</code> is supported across all browsers that support SVG.</p>
<h3 id="heading-5-how-to-use-svg-as-an">5. How to use SVG as an <code>&lt;iframe&gt;</code></h3>
<p>Even though this isn't advisable, you can also add an SVG image using an <code>&lt;iframe&gt;</code> as seen in the demo below.</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-5-co3hg?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<p>Just keep in mind, though, that <code>&lt;iframe&gt;</code>s can be difficult to maintain and will be bad for your site's Search Engine Optimization (SEO).</p>
<p>Using <code>&lt;iframe&gt;</code> also defeats the purpose of the <em>Scalable</em> in the name <em>Scalable Vector Graphics</em> because SVG images added with this format are not scalable.</p>
<h3 id="heading-6-how-to-use-svg-as-an">6. How to use SVG as an <code>&lt;embed&gt;</code></h3>
<p>The HTML <code>&lt;embed&gt;</code> element is another way to use an SVG image in HTML and CSS using this syntax: <code>&lt;embed src="happy.svg" /&gt;</code>.</p>
<p>Keep in mind, however, that this method has limitations, too. According to MDN, most modern browsers have deprecated and removed support for browser plug-ins. This means that relying upon <code>&lt;embed&gt;</code> is generally not wise if you want your site to be operable on the average user's browser.</p>
<p>Below is a demo of using the HTML <code>&lt;embed&gt;</code> element to add an SVG image.</p>
<div class="embed-wrapper"><iframe src="https://codesandbox.io/embed/svg-demo-6-iwy0s?fontsize=14&amp;hidenavigation=1&amp;theme=dark" style="width:100%;height:500px;border:0;border-radius:4px;overflow:hidden" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" title="Embedded content" loading="lazy"></iframe></div>

<h2 id="heading-conclusion">Conclusion</h2>
<p>I hope you were able to learn about the different ways of using SVG images in CSS and HTML. This will hopefully guide you towards choosing the right method when adding SVG images to a website.</p>
<p>If you have any questions, you can send me a <a target="_blank" href="https://twitter.com/Didicodes">message on Twitter</a>, and I'll be happy to answer every single one.</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[ CSS Background Image – How to Add an Image URL to Your Div ]]>
                </title>
                <description>
                    <![CDATA[ By Amy Haddad Say you want to put an image or two on a webpage. One way is to use the background-image CSS property.  This property applies one or more background images to an element, like a <div>, as the documentation explains. Use it for aesthetic... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-add-an-image-url-to-your-div/</link>
                <guid isPermaLink="false">66d45d9dcc7f04d2549a3730</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ css properties ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sun, 05 Apr 2020 11:22:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/w-qjCHPZbeXCQ-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Amy Haddad</p>
<p>Say you want to put an image or two on a webpage. One way is to use the <strong><code>background-image</code></strong> CSS property. </p>
<p>This property applies one or more background images to an element, like a <strong><code>&lt;div&gt;</code>,</strong> as the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-image">documentation</a> explains. Use it for aesthetic reasons, such as adding a textured background to your webpage.</p>
<h1 id="heading-add-an-image">Add an Image</h1>
<p>It’s easy to add an image using the <code>background-image</code> property. Just provide the path to the image in the <code>url()</code> value.</p>
<p>The image path can be a URL, as shown in the example below:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
   <span class="hljs-comment">/* Background pattern from Toptal Subtle Patterns */</span>
   <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://amymhaddad.s3.amazonaws.com/morocco-blue.png"</span>);
   <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;
   <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
}
</code></pre>
<p>Or it can be a local path. Here’s an example:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
   <span class="hljs-comment">/* Background pattern from Toptal Subtle Patterns */</span>
   <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;
   <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
   <span class="hljs-attribute">background-image</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">"./images/oriental-tiles.png"</span>);
}
</code></pre>
<h1 id="heading-add-multiple-images">Add Multiple Images</h1>
<p>You can apply multiple images to the <code>background-image</code> property.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
<span class="hljs-comment">/* Background pattern from Toptal Subtle Patterns */</span>
   <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;
   <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
   <span class="hljs-attribute">background-image</span>: 
       <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://amymhaddad.s3.amazonaws.com/morocco-blue.png"</span>),
       <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://amymhaddad.s3.amazonaws.com/oriental-tiles.png"</span>);
   <span class="hljs-attribute">background-repeat</span>: no-repeat, no-repeat;
   <span class="hljs-attribute">background-position</span>: right, left; 
}
</code></pre>
<p>That’s a lot of code. Let’s break it down.</p>
<p>Separate each image <code>url()</code> value with a comma.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">background-image</span>: 
    <span class="hljs-selector-tag">url</span>("<span class="hljs-selector-tag">https</span>://<span class="hljs-selector-tag">amymhaddad</span><span class="hljs-selector-class">.s3</span><span class="hljs-selector-class">.amazonaws</span><span class="hljs-selector-class">.com</span>/<span class="hljs-selector-tag">morocco-blue</span><span class="hljs-selector-class">.png</span>"),
    <span class="hljs-selector-tag">url</span>("<span class="hljs-selector-tag">https</span>://<span class="hljs-selector-tag">amymhaddad</span><span class="hljs-selector-class">.s3</span><span class="hljs-selector-class">.amazonaws</span><span class="hljs-selector-class">.com</span>/<span class="hljs-selector-tag">oriental-tiles</span><span class="hljs-selector-class">.png</span>");
</code></pre>
<p>Now position and enhance your images by applying additional properties.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">background-repeat</span>: <span class="hljs-selector-tag">no-repeat</span>, <span class="hljs-selector-tag">no-repeat</span>;
<span class="hljs-selector-tag">background-position</span>: <span class="hljs-selector-tag">right</span>, <span class="hljs-selector-tag">left</span>;
</code></pre>
<p>There are several <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Backgrounds_and_Borders/Using_multiple_backgrounds">sub-properties</a> you can add to your background images, such as <strong><code>background-repeat</code></strong> and <strong><code>background-position</code></strong>, which we used in the above example. You can even add <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/gradient">gradients</a> to a background image.</p>
<p>See what it looks like when we put everything together.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/amymhaddad/embed/VwLqWbm" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h1 id="heading-order-matters">Order Matters</h1>
<p>The order that you list your images in matters because of the stacking order. That means the first image listed is nearest to the user, according to the <a target="_blank" href="https://www.w3.org/TR/css-backgrounds-3/#layering">documentation</a>. Then, the next one, and the next, and so on. </p>
<p>Here’s an example.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">div</span> {
<span class="hljs-comment">/* Background pattern from Toptal Subtle Patterns */</span>
   <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;
   <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
   <span class="hljs-attribute">background-image</span>: 
       <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://amymhaddad.s3.amazonaws.com/morocco-blue.png"</span>),
       <span class="hljs-built_in">url</span>(<span class="hljs-string">"https://amymhaddad.s3.amazonaws.com/oriental-tiles.png"</span>);
   <span class="hljs-attribute">background-repeat</span>: no-repeat, no-repeat;
}
</code></pre>
<p>We’ve listed two images in the code above. The first image (morocco-blue.png) will be in front of the second (oriental-tiles.png). Both images are the same size and lack opacity, so we only see the first image.</p>
<p>But if we move the second image (oriental-tiles.png) over to the right by 200 pixels, then you can see part of it (the rest remains hidden).</p>
<p>Here’s what it looks like when we put everything together.</p>
<div class="embed-wrapper">
        <iframe width="100%" height="350" src="https://codepen.io/amymhaddad/embed/oNXrXMo" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="CodePen embed" scrolling="no" allowtransparency="true" allowfullscreen="true" loading="lazy"></iframe></div>
<h2 id="heading-when-should-you-use-background-image">When Should You Use Background Image?</h2>
<p>There’s a lot to like about the <code>background-image</code> property. But there’s a drawback. </p>
<p>The image may not be accessible to all users, the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-image">documentation</a> points out, like those who use screen readers.</p>
<p>That’s because you can’t add textual information to the <code>background-image</code> property. As a result, the image will be missed by screen readers.</p>
<p>Use the <code>background-image</code> property only when you need to add some decoration to your page. Otherwise, use the HTML <strong><code>&lt;img&gt;</code></strong> element if an image has meaning or purpose, as the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/background-image">documentation</a> notes.</p>
<p>That way, you can add text to an image element, using the <strong><code>alt</code></strong> attribute, which <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img">describes the image</a>. The provided text will be picked up by screen readers.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"house"</span> 
       <span class="hljs-attr">src</span>=<span class="hljs-string">"./images/farnsworth_house.jpeg"</span>
       <span class="hljs-attr">alt</span>=<span class="hljs-string">"A glass house designed by Ludwig Mies van der Rohe located in Plano, Illinois."</span>&gt;</span>
</code></pre>
<p>Think of it this way: <code>background-image</code> is a CSS property, and CSS focuses on presentation or style; HTML focuses on semantics or meaning. </p>
<p>When it comes to images, you’ve got options. If an image is needed for decoration, then the <code>background-image</code> property may be a good choice for you.</p>
<p><em>I write about learning to program and the best ways to go about it (</em><a target="_blank" href="https://amymhaddad.com/">amymhaddad.com</a>).  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build an Image Slider with jQuery ]]>
                </title>
                <description>
                    <![CDATA[ This tutorial will walk you through building an image slider using the jQuery library. This tutorial will have four parts: HTML SCSS JS References HTML We will be using Bootstrap for this tutorial to keep things looking good, without spending a lo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-an-image-slider-with-jquery/</link>
                <guid isPermaLink="false">66c3502ebbe01f981047867a</guid>
                
                    <category>
                        <![CDATA[ HTML ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ jQuery ]]>
                    </category>
                
                    <category>
                        <![CDATA[ toothbrush ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Sat, 08 Feb 2020 01:57:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9cae740569d1a4ca3395.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>This tutorial will walk you through building an image slider using the <a target="_blank" href="https://jquery.com/">jQuery</a> library.</p>
<p><img src="https://discourse-user-assets.s3.amazonaws.com/original/2X/0/08d83a22c28da836a06853b1f1ea669b398326b9.gif" alt="GIF showing Slider in action" width="720" height="398" loading="lazy"></p>
<p>This tutorial will have four parts:</p>
<ul>
<li><a target="_blank" href="https://guide.freecodecamp.org/miscellaneous/guide-to-build-a-sliding-image-gallery/#html">HTML</a></li>
<li><a target="_blank" href="https://guide.freecodecamp.org/miscellaneous/guide-to-build-a-sliding-image-gallery/#scss">SCSS</a></li>
<li><a target="_blank" href="https://guide.freecodecamp.org/miscellaneous/guide-to-build-a-sliding-image-gallery/#js">JS</a></li>
<li><a target="_blank" href="https://guide.freecodecamp.org/miscellaneous/guide-to-build-a-sliding-image-gallery/#references">References</a></li>
</ul>
<h2 id="heading-html"><strong>HTML</strong></h2>
<p>We will be using <a target="_blank" href="http://getbootstrap.com/">Bootstrap</a> for this tutorial to keep things looking good, without spending a lot of time.</p>
<p>Our structure will be as follows:</p>
<pre><code class="lang-text">&lt;div class="container"&gt;

  &lt;!-- The wrapper for our slider --&gt;
  &lt;div class="slider"&gt;
    &lt;ul class="slides"&gt;&lt;!-- Each image will be inside this unordered list --&gt;&lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class="buttons"&gt;&lt;!-- Pause and play buttons will go in here --&gt;&lt;/div&gt;

&lt;/div&gt;
</code></pre>
<p>Inside our <code>ul</code> with the class of <code>slides</code> we will have the following:</p>
<pre><code class="lang-text">&lt;li class="slide"&gt;&lt;img src="#" /&gt;&lt;/li&gt;
&lt;li class="slide"&gt;&lt;img src="#" /&gt;&lt;/li&gt;
&lt;li class="slide"&gt;&lt;img src="#" /&gt;&lt;/li&gt;
&lt;li class="slide"&gt;&lt;img src="#" /&gt;&lt;/li&gt;
&lt;li class="slide"&gt;&lt;img src="#" /&gt;&lt;/li&gt;
</code></pre>
<p>Inside our <code>.buttons</code> class you should have the following:</p>
<pre><code class="lang-text">&lt;button type="button" class="btn btn-default pause"&gt;
    &lt;span class="glyphicon glyphicon-pause"&gt;&lt;/span&gt;
&lt;/button&gt;
&lt;button type="button" class="btn btn-default play"&gt;
    &lt;span class="glyphicon glyphicon-play"&gt;&lt;/span&gt;
&lt;/button&gt;
</code></pre>
<p>Here is an example of what your <code>html</code> should look like:</p>
<p>Note: You should replace the image <code>src</code> attribute with your own content.</p>
<pre><code class="lang-text">&lt;div class="container"&gt;

  &lt;div class="slider"&gt;
    &lt;ul class="slides"&gt;
      &lt;li class="slide"&gt;&lt;img src="https://unsplash.it/1280/720/?image=120" /&gt;&lt;/li&gt;
      &lt;li class="slide"&gt;&lt;img src="https://unsplash.it/1280/720/?image=70" /&gt;&lt;/li&gt;
      &lt;li class="slide"&gt;&lt;img src="https://unsplash.it/1280/720/?image=50" /&gt;&lt;/li&gt;
      &lt;li class="slide"&gt;&lt;img src="https://unsplash.it/1280/720/?image=170" /&gt;&lt;/li&gt;
      &lt;li class="slide"&gt;&lt;img src="https://unsplash.it/1280/720/?image=190" /&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;

  &lt;div class="buttons"&gt;
    &lt;button type="button" class="btn btn-default pause"&gt;
      &lt;span class="glyphicon glyphicon-pause"&gt;&lt;/span&gt;
    &lt;/button&gt;
    &lt;button type="button" class="btn btn-default play"&gt;
      &lt;span class="glyphicon glyphicon-play"&gt;&lt;/span&gt;
    &lt;/button&gt;
  &lt;/div&gt;

&lt;/div&gt;
</code></pre>
<h2 id="heading-scss"><strong>SCSS</strong></h2>
<p>We are using <a target="_blank" href="http://sass-lang.com/">Sass</a> and the SCSS syntax so we can nest and use variables</p>
<p><img src="https://forum.freecodecamp.com/images/emoji/emoji_one/heart_decoration.png?v=2" alt=":heart_decoration:" width="600" height="400" loading="lazy"></p>
<p>We can use the following SCSS to define our styling:</p>
<pre><code class="lang-text">// Variables
$width: 720px;

.slider {
  width: $width;
  height: 400px;
  overflow: hidden;
  margin: 0 auto;
  text-align: center;

  .slides {
    display: block;
    width: 6000px;
    height: 400px;
    margin: 0;
    padding: 0;
  }

  .slide {
    float: left;
    list-style-type: none;
    width: $width;
    height: 400px;

    img {
      width: 100%;
      height: 100%;
    }
  }
}

.buttons {
  margin: 0;
  width: $width;
  position: relative;
  top: -40px;
  margin: 0 auto;

  .play {
    display: none;
  }

  .btn {
    display: flex;
    margin: 0 auto;
    text-align: center;
  }
}
</code></pre>
<h2 id="heading-js"><strong>JS</strong></h2>
<h4 id="heading-variables"><strong>Variables</strong></h4>
<p><em>In the following code snippet, we define variables used later in our code.</em></p>
<pre><code class="lang-text">var animationSpeed = 1000; // How quickly the next slide animates.
var pause = 3000; // The pause between each slide.
</code></pre>
<p>We will use a blank variable where we will call the <code>setInterval</code> method:</p>
<pre><code class="lang-text">var interval;
</code></pre>
<h4 id="heading-animation-we-will-wrap-our-slider-animations-inside-a-function"><strong>Animation We will wrap our slider animations inside a function:</strong></h4>
<pre><code class="lang-text">function startSlider() {}
</code></pre>
<p>We are using the <code>setInterval()</code> native JavaScript method to automate the contents of the function on a time based trigger.</p>
<pre><code class="lang-text">interval = setInterval(function() {}, pause);
</code></pre>
<p>We use the <code>pause</code> variable to see how many milliseconds to wait before calling the function again. Read more on the native <code>setInterval</code> method here: <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval">https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval</a>. Inside our function we will use jQuery to fade between slides at the speed of the animationSpeed variable:</p>
<pre><code class="lang-text">$('.slides &gt; li:first')
  .fadeOut(animationSpeed)
  .next()
  .fadeIn(animationSpeed)
  .end()
  .appendTo('.slides');
</code></pre>
<p>We are targeting the first slide using <code>$('.slides &gt; li:first')</code>. - <code>.fadeOut(animationSpeed)</code> will fade the first slide out and then using <code>.next()</code>, we move to the next slide. - Once we have moved to the next slide, we will fade it in: <code>.fadeIn(animationSpeed)</code>. - This sequence will continue until the last slide (<code>.end()</code>), then we stop the animation. We will now call the <code>startSlider</code> function to start the animation:</p>
<p>startSlider();</p>
<h4 id="heading-play-and-pause-this-feature-is-optional-but-quite-easy-to-implement-we-will-hide-the-play-button-so-we-dont-see-both-the-play-and-pause-buttons"><strong>Play and Pause <em>This feature is optional, but quite easy to implement.</em> We will hide the play button, so we don’t see both the play and pause buttons:</strong></h4>
<pre><code class="lang-text">$('.play').hide(); // Hiding the play button.
</code></pre>
<p>We will now create our pause button (automatically shown on page load):</p>
<pre><code class="lang-text">$('.pause').click(function() {
    clearInterval(interval);
    $(this).hide();
    $('.play').show();
});
</code></pre>
<p>We will call our function every time the pause button is clicked using jQuery. - We will remove the interval using the <code>clearInterval</code> method and using our <code>interval</code> variable as the parameter, indicating which interval to stop. - Because our slider is paused, we will hide the pause button using <code>$(this).hide();</code>. Note: we are using <code>this</code>, which will refer to what our parent is calling i.e. <code>.pause</code>. - We will then show our play button so the user can resume the animation: <code>$('.play').show();</code>. The following code sets up our play button (automatically hidden on page load):</p>
<p>$(‘.play’).click(function() { startSlider(); $(this).hide(); $(‘.pause’).show(); });</p>
<p>We will call our function every time the play button is clicked using jQuery.</p>
<ul>
<li>We will start or restart the interval using the <code>startSlider</code> function.</li>
<li>Because our slider is currently playing, we will hide the play button using <code>$(this).hide();</code>. Note: we are using <code>this</code>, which will refer to what our parent is calling i.e. <code>.play</code>.</li>
<li>We will then show our pause button so the user can stop the animation at will: <code>$('.pause').show();</code>.</li>
</ul>
<h2 id="heading-references"><strong>References</strong></h2>
<ul>
<li>Checkout the source code and example on <a target="_blank" href="https://codepen.io/atjonathan/pen/BKMxxq">CodePen</a> for this tutorial.</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to generate product images for Amazon, Instagram, Zalando, and Tmall ]]>
                </title>
                <description>
                    <![CDATA[ By Anton Garcia Diaz Millions of people have already shifted from traditional tv to online content, and from traditional malls to online stores. Because of this, e-commerce and marketing teams need to deploy and maintain strong online presences for t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/generation-of-product-images-for-amazon-zalando-tmall-instagram-asos/</link>
                <guid isPermaLink="false">66d45d9c052ad259f07e4a61</guid>
                
                    <category>
                        <![CDATA[ image ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image optimization  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ image processing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive images ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 26 Nov 2019 15:54:54 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/11/123brand.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Anton Garcia Diaz</p>
<p>Millions of people have already shifted from traditional tv to online content, and from traditional malls to online stores. Because of this, e-commerce and marketing teams need to deploy and maintain strong online presences for their businesses. </p>
<p>This usually means running the brand's own online store and having a presence in different marketplaces that cover different regions and population segments. The never-ending list of possible marketplaces in which to showcase, promote, and sell products just gets longer and longer.</p>
<p>To make matters worse, different marketplaces have different requirements and restrictions on images, which can add a burden for the devops and marketing teams. It's also a source of inconsistency in the public image of a brand.</p>
<p>Here, we'll review the main aspects to consider when setting up a clean pipeline for the seamless production of omnichannel images.</p>
<h2 id="heading-a-single-master-image-through-a-single-pipeline">A single master image through a single pipeline</h2>
<p>To simplify workflows and keep them sustainable, a good practice is to apply the principles of omnichannel to images. This basically means to set a single, easy to configure pipeline for the creation of variants, from the same master or pristine images. Under this approach, we can use <strong>the same product image for every channel</strong>. </p>
<p>Our pipeline should receive master images and produce the derivatives needed to feed the marketplaces. At a minimum, it should cope with a workflow like this.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/generation-of-variants/index.html">https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/generation-of-variants/index.html</a></div>
<p>Of course, a front-end and cloud storage are not necessary. The pipeline may just work by watching a hot folder and creating the variants as master images land there. We'll also take a look at this.</p>
<h2 id="heading-image-transformation-and-optimization">Image transformation and optimization</h2>
<p>Each web channel has its own web design and layout. As for images, this means different and specific aspect ratios. Besides, each marketplace usually has an image policy in place, which limits the resolution and the weight of the image and sets the admissible image format. Usually, it also specifies other style guidelines.</p>
<p>Let's look at the main operations we'll want to accomplish with our pipeline.</p>
<h3 id="heading-resizing-cropping-padding">Resizing, cropping, padding</h3>
<p>To change the aspect ratio of an image we may crop it or pad it. To get a squared image from a vertical one we may cut out the upper and bottom parts or we may fill in the left and right sides with white stripes. </p>
<p>There are open source tools – like ImageMagick – that allow you to perform these operations effectively. Resizing an image with ImageMagick to limit its maximum dimensions to 800 px is as simple as this:</p>
<pre><code>convert input.jpg -resize <span class="hljs-number">800</span>x800 resized.jpg
</code></pre><p>This instruction respects the aspect ratio. If the original image is not squared, then the resized image has one dimension lower than 800 px.  Let's say the image is vertical and we want it for Tmall, which requires a squared image of 800x800 px. Then we may pad it like this:</p>
<pre><code>convert resized.jpg  -gravity center -extent <span class="hljs-number">800</span>x800 padded.jpg
</code></pre><p>Also, we may simply crop it to fit the dimensions:</p>
<pre><code>convert input.jpg -gravity Center  -crop <span class="hljs-number">800</span>x800+<span class="hljs-number">0</span>+<span class="hljs-number">0</span> +repage crop.jpg
</code></pre><p>While some marketplaces like Tmall encourage padding images with white stripes and branding them with logos to use them in category pages, others like Amazon or Lamoda forbid this practice. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/crop_pad.png" alt="Image" width="600" height="400" loading="lazy">
<em>Cropping (left), Resizing (center), Resizing and padding (right)</em></p>
<p>When we pad an image to match the aspect ratio, we don’t risk cropping out important parts. In fact, padding is a trick to keep the aspect ratio unchanged. However, the risk is real when we crop the image. </p>
<p>So, it is a good practice to ensure in the studio that we comply with some composition requirements set by each channel. We should produce master images with a view of the product compatible with the different aspect ratios that we'll deliver.</p>
<h3 id="heading-smart-cropping">Smart cropping</h3>
<p>There are algorithms inspired by human attention and aesthetic perception that provide an enhanced protection against bad automatic crops. In the next example, with smart image cropping (white line) we avoid cutting the face unlike a simple center cropping (red line) would do.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/smart-cropping-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>Example of smart cropping with a <a target="_blank" href="https://abraia.me/workflows/">cloud service</a> vs center cropping</em></p>
<p>This option is available in some cloud services. If we're going to use it, we should verify that it works properly for us because many solutions only use an attention map and do not consider aesthetic aspects. Usually, choosing a number of representative images, making some tests with them, and finally verifying the results is enough to get a good grasp.</p>
<h3 id="heading-overlaying-logos-and-text">Overlaying logos and text</h3>
<p>We may also need to add our brand logo or to add a message to the image by overlaying a vector graphic or a text. Moreover, in many cases we need some content localization strategy in place – like tailoring discounts and language to a market region. Sticking to our example, with ImageMagick we can overlay text on a padded image.</p>
<pre><code>convert -fill black -pointsize <span class="hljs-number">70</span> -gravity center -draw <span class="hljs-string">"rotate -90 text 0,-330 'MyBrandHere'"</span> padded.jpg padded-<span class="hljs-keyword">with</span>-brand.jpg
</code></pre><p>Once we configure it for one image, we may apply it to any other with the same dimensions. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/11/brand.png" alt="Image" width="600" height="400" loading="lazy">
<em>Examples of batch image branding using <a target="_blank" href="https://abraia.me/workflows/">Abraia's cloud service</a></em></p>
<p>Otherwise, handling typographies and different settings may end being tricky in workflows with certain complexity. In this regard, a <a target="_blank" href="https://abraia.me/workflows/">cloud service</a> usually provides a front-end to make the configuration intuitive and fast, and more convenient to handle. It also deals with other stuff like typographies or quality preservation in image recompression. </p>
<h2 id="heading-the-workflows">The workflows</h2>
<p>There are many ways to deploy an image processing pipeline. Depending on the flow rate of images, we may need to support different types of workflows.  </p>
<h3 id="heading-batch-processing">Batch processing</h3>
<p>In the most simple case – when the flow rate is low – a batch image processing solution may be enough. With ImageMagick, we can use <em>mogrify</em> (instead of convert) to process all the images inside a folder. </p>
<p>In certain cases, like image versions with a text in different languages, we may need to code a script, but that's not a big deal either. To make it even easier, we may use a cloud batch processing tool in which we drop images and it gives us back all the variants we need, like in the video at the beginning of the post.</p>
<h3 id="heading-hot-folders">Hot folders</h3>
<p>For in-house deployments where we need something more than simple batch image processing, the use of hot folders may be a good option. In this case, we should set a worker that watches a folder. Any time an image lands the folder the watcher triggers the process that creates all the variants we need.</p>
<p>In this regard, Gulp comes very handy to implement a folder watching pipeline. <a target="_blank" href="https://github.com/abraia/workflows">This GitHub repository brings a ready-to-use implementation of hot folder</a> based on Gulp. It allows us to transform images using Abraia's cloud service or optimize them using Imagemin (an open source solution). Once installed, the watcher is easily started with just one command in the terminal.</p>
<pre><code>$ gulp
</code></pre><p>This video shows the process at work.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/hot-folder-gulp/index.html">https://store.abraia.me/05bf471cbb3f9fa9ed785718e6f60e28/product-images-for-amazon-zalando-tmall-lamoda-ssg/hot-folder-gulp/index.html</a></div>
<h3 id="heading-full-cloud">Full cloud</h3>
<p>Cloud services usually bring the most flexible and fast-to-deploy solution. Still, there are different ways to go full cloud. In the most simple approach from a user perspective, an image management and optimization service takes charge of the transformation. It also manages the delivery to end users (through a CDN) or other web channels like marketplaces and social networks. The user only needs to upload the master images and to configure the transformations, usually with an intuitive graphic interface.</p>
<p>In medium to large companies that manage their own cloud, services from different providers are usually combined. In this case, we are likely to have to manage private and public buckets. We can have a service accessing a bucket, creating the variants, and delivering the resources or just returning them to a different bucket. </p>
<p>Also, a cloud pipeline may be partially implemented in-house. In this case we have endless possibilities. However, such development effort only makes sense when no service complies with the requirements and there is a justified need for a tailored solution.</p>
<h2 id="heading-summary">Summary</h2>
<p>Studio shooting and photography retouching are time-consuming and costly operations. Being able to use the same master material everywhere is very important to keep times and cost under control.</p>
<p>We have reviewed the main aspects of a complete pipeline in charge of creating image variants. On one hand, we looked at the transformations you need to perform from resizing, cropping, or padding, to the overlay of texts and graphics. On the other, we looked at the workflows to implement from batch processing to hot folders or full cloud solutions. We have reviewed some important open source resources (like ImageMagick or Gulp) that make it possible to implement a pipeline you develop yourself. </p>
<p>In the end, there are two main factors to consider when deciding whether to use an in-house or a cloud service. First, you must evaluate your willingness to take on the development effort. Second, you need to decide what features you require, from an easy to use interface for the configuration of variants to advanced features like smart cropping.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
