<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Colby Fayock</title>
    <description>The latest articles on DEV Community by Colby Fayock (@colbyfayock).</description>
    <link>https://dev.to/colbyfayock</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F186511%2Fc8cb9a0a-e3bb-4f6e-a332-c45617c1455a.png</url>
      <title>DEV Community: Colby Fayock</title>
      <link>https://dev.to/colbyfayock</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/colbyfayock"/>
    <language>en</language>
    <item>
      <title>Crafting a React/Next.js Single Page Application Optimized for SEO</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Thu, 10 Jun 2021 20:59:21 +0000</pubDate>
      <link>https://dev.to/colbyfayock/crafting-a-react-next-js-single-page-application-optimized-for-seo-54fk</link>
      <guid>https://dev.to/colbyfayock/crafting-a-react-next-js-single-page-application-optimized-for-seo-54fk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;In a rush? Skip to tutorial steps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What's the first thing you do when you are looking for something?&lt;/p&gt;

&lt;p&gt;If you're like me, you probably pull out your phone and search for it on Google. It makes optimizing websites for search engines more important than ever. And as a developer, I get it, SEO is a critical part of any business’ online presence. It's my job to be sure our tools can support that effort of being easily visible on search engine results pages. &lt;/p&gt;

&lt;p&gt;And since React is the &lt;a href="https://medium.com/javascript-scene/top-javascript-frameworks-and-tech-trends-for-2021-d8cb0f7bda69" rel="noopener noreferrer"&gt;most popular JavaScript framework&lt;/a&gt;, these tools will most likely be related to it or React frameworks like Next.js.&lt;/p&gt;

&lt;p&gt;But, how can we be sure our React dynamic applications are SEO-friendly for our favorites robot crawlers to understand?&lt;/p&gt;

&lt;p&gt;That's when the real work comes in. Stop googling: "SEO with react" 'cause you're are at the right place to get started, my friends!&lt;/p&gt;

&lt;p&gt;It’s exactly what we'll explore today. How Next.js can help give an SEO boost to our React-powered SPA.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205868%2Fseo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205868%2Fseo.png" alt="Single Page Application SEO Next.js"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk through the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What’s a SPA?&lt;/li&gt;
&lt;li&gt;What are the challenges with SPA SEO?&lt;/li&gt;
&lt;li&gt;Why is SEO important?&lt;/li&gt;
&lt;li&gt;What is Next.js?&lt;/li&gt;
&lt;li&gt;How to get started building SEO-friendly React apps with Next.js?&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;For more tech-agnostic info about single-page application SEO, check out this &lt;a href="https://snipcart.com/spa-seo" rel="noopener noreferrer"&gt;in-depth guide&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is a SPA?
&lt;/h2&gt;

&lt;p&gt;A SPA (or Single Page Application) is a type of web application that provides a dynamic and interactive experience all from one point of entry.&lt;/p&gt;

&lt;p&gt;Traditionally, you might be more familiar with a server-side approach, where each page of your website has its own “route” (or page URL), but with a SPA, you have a single route that loads up the entire website in the browser using &lt;a href="https://snipcart.com/blog/javascript-beginner-intro-exercises" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s a little easier to get your head around it with an example. If you’re building a React application, React needs to "mount" onto a page element. You can do this by serving a page like index.html to your visitor, then in the browser, React will provide that mounting action based on your instructions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205856%2Fcreate-react-app-mounting-point.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205856%2Fcreate-react-app-mounting-point.png" alt="Create React App mount point"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that page mounts, React kicks in and enables you to do whatever you want. Whether it’s providing simple things for the visitor to interact with or providing some routing mechanism to change pages, in this example, that entire experience originated from that single page.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes single-page application SEO challenging?
&lt;/h2&gt;

&lt;p&gt;Part of the issue of serving an entire application based on a single entry point (index.html) is when Google is trying to look at that URL, they’re only ever going to be able to see the content and metadata from that single initial page.&lt;/p&gt;

&lt;p&gt;This limits what pages you can make available to Google, ultimately hurting your ability to index more content. It’s that indexed content that makes your website or application discoverable by search engines.&lt;/p&gt;

&lt;p&gt;Also, traditionally, a single-page application leans heavily on JavaScript to provide a dynamic experience. For many simple use cases, this might be completely fine, as &lt;a href="https://developers.google.com/search/docs/guides/javascript-seo-basics" rel="noopener noreferrer"&gt;Google can support&lt;/a&gt; a limited amount of JavaScript when crawling the page, but this isn't true of all search engines.&lt;/p&gt;

&lt;p&gt;With these challenges, we start to lose our competitive advantage when trying to make use of one of the biggest potential traffic sources on the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is SEO important?
&lt;/h2&gt;

&lt;p&gt;SEO (Search Engine Optimization) is the practice of helping search engines more easily read and understand what your website or application is about.&lt;/p&gt;

&lt;p&gt;This is critical if your goal is to bring as many people as you can to your website. The goal of people researching on the internet is to ultimately find something, and that something can be your business or the content you’re trying to promote. More traffic (visitors) means more potential sales (or customers) for your business.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205866%2Fsnipcart-seo-google.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205866%2Fsnipcart-seo-google.png" alt="SEO for “Add a Shopping Cart to Any Websites in Minutes”"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Search engines are constantly getting smarter, with hardworking teams at Google, Bing, Duck Duck Go, and other engines constantly fine-tuning search algorithms. But we wouldn’t need to write this article if they were perfect. While they might be able to figure out what your blog post is broadly about or what types of products your business sells, it’s limited by what information you provide and how you provide it.&lt;/p&gt;

&lt;p&gt;If you’re solely relying on a SPA that is hard to crawl and doesn’t give much information on that first and only page that Google can see, you’re missing out on potential opportunities. People could have found your content instead of your competitors when searching.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Next.js, and how does it help with SEO?
&lt;/h2&gt;

&lt;p&gt;The awesome thing about the web is that not only are search engines getting smarter, but the tools we can use as developers are becoming more mature. It gives us ways to solve our SEO needs without sacrificing any functionality that makes a SPA great.&lt;/p&gt;

&lt;p&gt;Next.js is a web framework that sits on top of React, providing a bunch of features out of the box that can take our applications to another level.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205864%2Fnextjs-homepage-features.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205864%2Fnextjs-homepage-features.png" alt="Next.js homepage features list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the example of our traditional SPA, we had a single index.html file. React would mount the application in the browser and handle any interactions and page navigation in that file.&lt;/p&gt;

&lt;p&gt;A different approach would be to have .html files for all of our pages. For each visited page, React would mount the application and content for that particular page (e.g., About page, Contact page) rather than loading from the initial homepage.&lt;/p&gt;

&lt;p&gt;To do that, Next.js has a few different techniques and APIs that developers can interface with to make sure we’re providing as much SEO value as we can.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static Site Generation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://snipcart.com/blog/choose-best-static-site-generator" rel="noopener noreferrer"&gt;Static Site Generation (SSG)&lt;/a&gt; is the practice of pre-rendering some or all of the pages of a website/application ahead of the browser at compile time. The index.html would include most, if not all, of the experience that will get loaded in the browser.&lt;/p&gt;

&lt;p&gt;This works wherever the website or application is compiled from, that server or environment will bring in any data sources and use React to build the website just like it would inside the browser, but export it into an HTML file. This file would then get served to the visitor.&lt;/p&gt;

&lt;p&gt;React would still “hydrate” the page and provide the ability to add a more dynamic experience. However, by pre-rendering, you’re able to reduce the amount of work the browser has to do to get your visitor the experience you want to give them.&lt;/p&gt;

&lt;p&gt;Each of these pages is located in individual “routes,” like mentioned before. Visitors, or in our case, search engine crawlers, would then be able to go directly to the page and see the content specific to that page.&lt;/p&gt;

&lt;p&gt;This means that not only can we have page-specific metadata, like a title and description, but the search engine can also read and understand that page’s content and recommend it to people based on their searches.&lt;/p&gt;

&lt;p&gt;Nevertheless, rendering pages at compile time comes with its limitation. The information that can be sent immediately to the browser is limited because of its static nature. While we can still load that dynamically in the browser, some use cases may need a completely dynamic experience that could be challenging to accomplish.&lt;/p&gt;

&lt;h3&gt;
  
  
  Server-side Rendering
&lt;/h3&gt;

&lt;p&gt;Server-side Rendering (SSR) provides a similar concept to Static Site Generation. Still, instead of compiling each page ahead of time into static files, that experience will be rendered by React at request time. For instance, if your visitor is trying to visit the Contact page (/contact), the server will recognize the route that is being visited, fetch all information related to that page, compile the HTML, and return it as part of the initial response.&lt;/p&gt;

&lt;p&gt;Similar to SSG, using this technique, you can leverage the ability to provide page-specific information and context to both our visitors and search engines. This way, we make sure our content is as searchable as it can be.&lt;/p&gt;

&lt;p&gt;While both options work well for providing good SEO, there are some tradeoffs with SSG and SSR. We won't get into this article, but it should be considered when &lt;a href="https://www.netlify.com/blog/2020/12/02/next.js-should-i-use-ssr-or-ssg/" rel="noopener noreferrer"&gt;making the decision&lt;/a&gt; for your website or application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next.js Head Component
&lt;/h3&gt;

&lt;p&gt;Regardless of the option you choose, a challenging part of using tools like React for building a web page is that these applications get mounted into the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body" rel="noopener noreferrer"&gt;&lt;/a&gt; of an HTML page. This means that you don’t have direct access, without &lt;a href="https://github.com/nfl/react-helmet" rel="noopener noreferrer"&gt;additional tools&lt;/a&gt;, to make any changes to places like the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head" rel="noopener noreferrer"&gt;&lt;/a&gt; of a website. It’s traditionally where a lot of key metadata lives for describing your content to search engines.&lt;/p&gt;

&lt;p&gt;This includes things like your title, description, and any Open Graph data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Add a Shopping Cart to Any Website in Minutes - Snipcart&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Add a shopping cart to your site in minutes. Works with any site builder, CMS, and framework. 20 000+ merchants trust our e-commerce solution for their website. Join them!"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Add a Shopping Cart to Any Website in Minutes - Snipcart"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Add a shopping cart to your site in minutes. Works with any site builder, CMS, and framework. 20 000+ merchants trust our e-commerce solution for their website. Join them!"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://snipcart.com/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luckily, Next.js ships with a &lt;a href="https://nextjs.org/docs/api-reference/next/head" rel="noopener noreferrer"&gt;H&lt;/a&gt;&lt;a href="https://nextjs.org/docs/api-reference/next/head" rel="noopener noreferrer"&gt;ead component&lt;/a&gt; out of the box that we can leverage to make sure all of our pages include those important details that need to get rendered into our page.&lt;/p&gt;

&lt;p&gt;You can first import the head component to make it work, then include it as a child of a Next.js page. You can then add anything you want to the Head.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;IndexPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Add a Shopping Cart to Any Website in Minutes - Snipcart&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Add a shopping cart to your site in minutes. Works with any site builder, CMS, and framework. 20 000+ merchants trust our e-commerce solution for their website. Join them!"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Add a Shopping Cart to Any Website in Minutes - Snipcart"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Add a shopping cart to your site in minutes. Works with any site builder, CMS, and framework. 20 000+ merchants trust our e-commerce solution for their website. Join them!"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://snipcart.com/"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next.js will recognize that metadata and do the hard work of lifting it up to the right location in your HTML document when the page is being rendered.&lt;/p&gt;

&lt;p&gt;This lets us end up with both the power of dynamic React pages and the ability to craft that information for Google carefully!&lt;/p&gt;

&lt;h2 id="tutorial"&gt; Getting started with building SEO-friendly React apps with Next.js &lt;/h2&gt;

&lt;p&gt;Now let’s see how this works in action!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Feel free to follow the steps in this video!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8BrZeaw3sLQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you enjoy this, feel free to like, share &amp;amp; subscribe to his channel! :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We’ll start by building a React application from scratch then using the Next.js Head component to add metadata to our pages.&lt;/p&gt;

&lt;p&gt;Because we gain the ability to manage that metadata through various pages with Next.js, we’ll look at how we can customize it for new static pages and generate that metadata for dynamic pages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 0: Creating a new React app with Next.js
&lt;/h3&gt;

&lt;p&gt;We can start by creating a new Next.js application from scratch using &lt;a href="https://nextjs.org/docs/api-reference/create-next-app" rel="noopener noreferrer"&gt;Create Next App&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In your terminal, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    yarn create next-app my-seo-app
    &lt;span class="c"&gt;# or&lt;/span&gt;
    npx create-next-app my-seo-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: you can update &lt;code&gt;my-seo-app&lt;/code&gt; to whatever name you'd like to give the project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After running this command, Next.js will make a local copy of a starter application template and install the dependencies to get the project ready to go.&lt;/p&gt;

&lt;p&gt;Once it’s finished, you can navigate to that directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="nb"&gt;cd &lt;/span&gt;my-seo-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can start up your Next.js development server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    yarn dev
    &lt;span class="c"&gt;# or&lt;/span&gt;
    npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When loaded, Next.js will let you know the server is running at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;. If you open that up in your browser, you can see your new Next.js site!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205857%2Fnew-nextjs-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205857%2Fnew-nextjs-app.png" alt="New Next.js app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, feel free to look around the code inside of your new project and get ready for the next step!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Updating Next.js homepage SEO metadata
&lt;/h3&gt;

&lt;p&gt;When creating a new Next.js application, the framework starts with a homepage that includes some sample content.&lt;/p&gt;

&lt;p&gt;Additionally, its conventionality includes the Next.js Head component out of the box, first imported at the top of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As well as a few sample pieces of metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Create Next App&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Generated by create next app"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re making our Head component available in this instance, then adding a title, description, and a &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Favicon" rel="noopener noreferrer"&gt;favicon&lt;/a&gt;. If we view this page's source code in the browser, we can see this metadata as well as other things that Next.js is managing for us:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205861%2Fnextjs-default-metadata.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205861%2Fnextjs-default-metadata.png" alt="HTML Head managed by Next.js"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we wanted to update this with our own title and description, we can easily do so by simply changing those values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;My Clothing Store&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Come to my store for great apparel!"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205860%2Fnextjs-custom-metadata.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205860%2Fnextjs-custom-metadata.png" alt="Updated metadata in Next.js head"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we can see, Next.js is now using the values that we updated in our code.&lt;/p&gt;

&lt;p&gt;We can even change the image for our favicon located at &lt;code&gt;public/favicon.ico&lt;/code&gt; or completely change the link!&lt;/p&gt;

&lt;p&gt;If we wanted, we could also add more fields, such as the Open Graph title and description we saw earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;My Clothing Store&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Come to my store for great apparel!"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"My Clothing Store"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Come to my store for great apparel!"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://myclothingstore.com/"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just like before, Next.js updates that metadata.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205865%2Fnextjs-open-graph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205865%2Fnextjs-open-graph.png" alt="Updated metadata in Next.js app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This gives us the ability to craft our page's metadata exactly how we'd like it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-seo-app/commit/77b3d5dee371dc4e95269887c58e36daa9839999" rel="noopener noreferrer"&gt;Follow along with the commit on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Creating a new page with custom SEO metadata in Next.js
&lt;/h3&gt;

&lt;p&gt;As we’ve seen earlier, one of the main benefits of Next.js, when it comes to SEO, is the ability to provide direct links to individual pages. It’s giving us the ability to customize the metadata on that page for Google and our visitors.&lt;/p&gt;

&lt;p&gt;To do that, we can create a new page and see exactly how that works!&lt;/p&gt;

&lt;p&gt;Create a new file inside of the &lt;code&gt;pages&lt;/code&gt; directory called &lt;code&gt;about.js&lt;/code&gt;. Inside &lt;code&gt;pages/about.js&lt;/code&gt;, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../styles/Home.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;About&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
              About My Clothing Store
            &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new page called “About” at the route &lt;code&gt;/about&lt;/code&gt;. We can test this out by opening up our browser and visiting &lt;a href="http://localhost:3000/about" rel="noopener noreferrer"&gt;http://localhost:3000/about&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205859%2Fnextjs-about-page.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205859%2Fnextjs-about-page.png" alt="New about page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this page is simple, you can see that we could easily create a new page that can be accessed directly by the URL.&lt;/p&gt;

&lt;p&gt;Since we’re still inside React, we keep the same SPA capabilities, but we can additionally create content specific to each page without sacrificing SEO or user experience.&lt;/p&gt;

&lt;p&gt;To see how this works with metadata, let’s add the Next.js Head component. At the top of &lt;code&gt;pages/about.js&lt;/code&gt; import the Head component by adding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, inside of our wrapper &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element, let's add our Head component along with some metadata for our page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;About - My Clothing Store&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"The story behind My Clothing Store!"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"About - My Clothing Store"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"The story behind My Clothing Store!"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://myclothingstore.com/about"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like on our homepage, we’re adding a title, description, some Open Graph data, and even the same favicon as before.&lt;/p&gt;

&lt;p&gt;If we now open this up in our browser and look at the source, we can now see that our About page shows the metadata specific to that page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205858%2Fnextjs-about-page-metadata.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205858%2Fnextjs-about-page-metadata.png" alt="Metadata specific to our About page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By taking advantage of Next.js’s ability to have multiple pages with custom content and metadata, we’re able to help Google understand what each of our pages is about!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-seo-app/commit/4ec773c6bf731b52388b033dbc967e131ae6e516" rel="noopener noreferrer"&gt;Follow along with the commit on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Generating SEO metadata for dynamic pages in Next.js
&lt;/h3&gt;

&lt;p&gt;Adding a new static page with Next.js is relatively straightforward. We create a new file with the route we’d like to be available and generate a React component with the content. However, dynamic pages are a little trickier in that they’re dynamic.&lt;/p&gt;

&lt;p&gt;While we’re not going to get super deep into how &lt;a href="https://www.dummies.com/web-design-development/dynamic-web-pages-work/" rel="noopener noreferrer"&gt;dynamic pages work&lt;/a&gt;, we can still go through a basic example to get an idea of how we can dynamically manage the metadata on our page.&lt;/p&gt;

&lt;p&gt;Let’s get started by creating a new folder called &lt;code&gt;products&lt;/code&gt;, and inside of that folder, create a new file called &lt;code&gt;[productId].js&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: that’s not a typo. The filename should have the brackets around the &lt;code&gt;productId&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This will create a &lt;a href="https://nextjs.org/docs/routing/dynamic-routes" rel="noopener noreferrer"&gt;dynamic route&lt;/a&gt; in Next.js, allowing us to manage the way multiple pages look and work by defining which pages we want available and the dynamic data inside of it.&lt;/p&gt;

&lt;p&gt;Inside of &lt;code&gt;products/[productId].js&lt;/code&gt; add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../styles/Home.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Product ID: &lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;productId&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getStaticProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Product &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getStaticPaths&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we’re creating an example of routes inside Next.js with getStaticPaths to show how we can manage our dynamic metadata. Typically the paths would be built based on dynamic content, such as an API request or data file.&lt;/p&gt;

&lt;p&gt;A quick breakdown of what we’re doing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We're creating a new page with content similar to Step 2.&lt;/li&gt;
&lt;li&gt;We’re defining &lt;a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation" rel="noopener noreferrer"&gt;getStaticProps&lt;/a&gt;, which takes an argument including the dynamic value of a parameter. This parameter has the same name as the filename we created, &lt;code&gt;productId.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;When receiving that parameter value, we’re defining a simple title and productId, which will be passed in as props to our page component.&lt;/li&gt;
&lt;li&gt;We’re defining &lt;a href="https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation" rel="noopener noreferrer"&gt;getStaticPaths&lt;/a&gt;, where we’re using a new array to simulate a list of dynamic data.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: understanding how getStaticProps and getStaticPaths work isn't critical to understanding the use of dynamic data in our page component, but it will help follow along with the example!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Save that file, restart your development server, and now open &lt;code&gt;/products/5&lt;/code&gt; at &lt;a href="http://localhost:3000/products/5" rel="noopener noreferrer"&gt;http://localhost:3000/products/5&lt;/a&gt; in your browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205863%2Fnextjs-dynamic-product-page.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205863%2Fnextjs-dynamic-product-page.png" alt="Dynamic page with product #5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that we’re passing in the title and product ID dynamically from our page!&lt;br&gt;
Similarly, if we go to &lt;code&gt;/products/3&lt;/code&gt; (or any number between 1-5 in this example), we’ll see a similar page.&lt;/p&gt;

&lt;p&gt;Now that we’re using dynamic data on our page, we can use that same data to create our metadata.&lt;/p&gt;

&lt;p&gt;Just like before, first import the Next.js Head component at the top of the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the following to the page component of &lt;code&gt;pages/[productId].js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt; - My Clothing Store&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`Learn more about &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - My Clothing Store`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`Learn more about &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`https://myclothingstore.com/products/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;link&lt;/span&gt; &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, we’re adding the metadata to the Head component. However, this time, we’re dynamically setting all of our values’ metadata using our product’s title and product ID.&lt;/p&gt;

&lt;p&gt;If we open up the browser, we can see that our Head has those dynamic values!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205862%2Fnextjs-dynamic-page-metadata.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsnipcart.com%2Fmedia%2F205862%2Fnextjs-dynamic-page-metadata.png" alt="Screen Shot 2021-05-31 at 17.29.02.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-seo-app/commit/8d0ce71f0bc0a3f87037826f3f887f3bf1ba1196" rel="noopener noreferrer"&gt;Follow along with the commit on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Live demo &lt;a href="https://my-seo-app.netlify.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
GitHub repo &lt;a href="https://github.com/colbyfayock/my-seo-app" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What else can we do for better SEO?
&lt;/h2&gt;

&lt;p&gt;Using the Next.js Head component along with its page creation strategies can help us carefully craft our experience for both our visitors and Google. Still, there’s more we can do to make sure we’re always maximizing our SEO efforts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Analyze and monitor with Google Webmaster Tools and web.dev
&lt;/h3&gt;

&lt;p&gt;One of the first things we can always do is a test to make sure our website or application covers the basics.&lt;/p&gt;

&lt;p&gt;Luckily Google provides some free tools to handle this, including the &lt;a href="https://search.google.com/search-console/about" rel="noopener noreferrer"&gt;Search Console&lt;/a&gt; and &lt;a href="https://web.dev/" rel="noopener noreferrer"&gt;web.dev&lt;/a&gt; which will also test performance and accessibility. Performance and accessibility also happen to help SEO.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a sitemap
&lt;/h3&gt;

&lt;p&gt;Adding a sitemap to your website probably isn’t as critical as it used to be. Google can crawl your site pretty efficiently, but it’s still a helpful way to make sure all of your content is getting hit.&lt;/p&gt;

&lt;p&gt;While you can’t do this out of the box with Next.js, there are plugins to help, such as the &lt;a href="https://github.com/IlusionDev/nextjs-sitemap-generator" rel="noopener noreferrer"&gt;Next.js Sitemap Generator&lt;/a&gt; or a custom approach like the one I added to my &lt;a href="https://github.com/colbyfayock/next-wordpress-starter/blob/main/plugins/sitemap.js" rel="noopener noreferrer"&gt;Next.js WordPress Starter&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimizing for social media with Open Graph
&lt;/h3&gt;

&lt;p&gt;We lightly touched on Open Graph in the tutorial, but there’s a wide variety of metadata tags and use cases that make Open Graph an important part of your SEO work.&lt;/p&gt;

&lt;p&gt;Websites like Facebook and Twitter and apps like Discord and Slack all use Open Graph tags to pull in metadata, including what the link is about and which image they show.&lt;/p&gt;

&lt;p&gt;By optimizing your Open Graph tags, you can make sure those big images show up in social feeds whenever your website content is shared.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;SEO is a critical part of bringing in traffic to your website/application and, ultimately, your business. Ensuring things are working and looking as they should is an important part of how your business appears on search result pages.&lt;/p&gt;

&lt;p&gt;While React alone tends to struggle with providing a good overall SEO experience, we have many tools in our belt to help, like Next.js. These tools give us powerful frameworks to provide both a great experience to our customers and the search engines trying to crawl our websites.&lt;/p&gt;

&lt;p&gt;Regardless of the tools you use, be sure to test your SEO periodically. Just like maintaining any physical aspect of a business, we want to make sure our online presence is working for us as hard as it can!&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>seo</category>
    </item>
    <item>
      <title>Building Maps with React Leaflet - Course on egghead.io</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Fri, 04 Sep 2020 12:54:20 +0000</pubDate>
      <link>https://dev.to/colbyfayock/building-maps-with-react-leaflet-course-on-egghead-io-1mn7</link>
      <guid>https://dev.to/colbyfayock/building-maps-with-react-leaflet-course-on-egghead-io-1mn7</guid>
      <description>&lt;p&gt;If you’ve been following along with my work, I tend to talk about maps every so often.&lt;/p&gt;

&lt;p&gt;This includes tutorials like &lt;a href="https://www.colbyfayock.com/2020/03/how-to-create-a-coronavirus-covid-19-dashboard-map-app-with-gatsby-and-leaflet/" rel="noopener noreferrer"&gt;how to create a Coronavirus (COVID-19) statistics map&lt;/a&gt; or even &lt;a href="https://www.colbyfayock.com/2019/12/create-your-own-santa-tracker-with-gatsby-and-react-leaflet/" rel="noopener noreferrer"&gt;how to create your own Santa Tracker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;tl;dr my new course Building Maps with React Leaflet is now available on &lt;a href="https://egghead.io?af=atzgap" rel="noopener noreferrer"&gt;egghead.io&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why so much about maps?
&lt;/h2&gt;

&lt;p&gt;While maps aren’t my sole focus for the educational content I create, I’ve developed a passion for maps with my work at &lt;a href="http://element84.com/" rel="noopener noreferrer"&gt;Element 84&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With my day job, I’ve been working on building a satellite tasking dashboard, but before I even got started, I learned about how maps have made a huge impact in people’s lives at &lt;a href="https://2018.stateofthemap.us/" rel="noopener noreferrer"&gt;State of the Map&lt;/a&gt;. The stories are both inspiring and heartbreaking.&lt;/p&gt;

&lt;p&gt;As I learned more about maps, the more I realized the learning curve isn’t quite what people would expect. While there’s absolutely some complexity as you start digging deep into maps, getting started with a basic map has a much lower barrier to entry thanks to the tools available to use like &lt;a href="https://react-leaflet.js.org/en/" rel="noopener noreferrer"&gt;React Leaflet&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning maps with my new course!
&lt;/h2&gt;

&lt;p&gt;That’s what led me to put my time into developing this Building Maps with React Leaflet course with the &lt;a href="https://egghead.io?af=atzgap" rel="noopener noreferrer"&gt;egghead.io&lt;/a&gt; team.&lt;/p&gt;

&lt;p&gt;I walk you through building a map from scratch, starting off with essentially a clone version of &lt;a href="https://create-react-app.dev/" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt; with a few tweaks to make it easier to focus on learning about maps.&lt;/p&gt;

&lt;p&gt;Here’s what you’ll learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to build a map from scratch in a React app&lt;/li&gt;
&lt;li&gt;How to add markers and shapes to a map&lt;/li&gt;
&lt;li&gt;About geospatial data formats and how to create your own&lt;/li&gt;
&lt;li&gt;How to wrangle that data and visualize that data on a map&lt;/li&gt;
&lt;li&gt;How to use geolocation features to personalize the map&lt;/li&gt;
&lt;li&gt;How to customize the map with imagery and custom markers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After completing this course, you’ll be ready to build maps into your React apps for a ton of use cases, whether it’s visualizing geographical data like a pandemic or adding a store locator to your company’s website.&lt;/p&gt;

&lt;p&gt;I’d love for you to take this journey with me and I’d love to hear any feedback.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://egghead.io/courses/build-maps-with-react-leaflet" rel="noopener noreferrer"&gt;Build Maps with React Leaflet&lt;/a&gt; on &lt;a href="https://egghead.io?af=atzgap" rel="noopener noreferrer"&gt;egghead.io&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  On a personal note, this is my first course!
&lt;/h2&gt;

&lt;p&gt;Thanks to the egghead.io team for all the support through this process. Working through my first course was challenging, but it was certainly rewarding.&lt;/p&gt;

&lt;p&gt;I hope you all enjoy learning maps with my course as much as I enjoyed putting it together.&lt;/p&gt;

</description>
      <category>react</category>
      <category>leaflet</category>
      <category>maps</category>
      <category>course</category>
    </item>
    <item>
      <title>How to Build Tech Communities in a World of Pandemic</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Wed, 01 Jul 2020 21:01:24 +0000</pubDate>
      <link>https://dev.to/colbyfayock/how-to-build-tech-communities-in-a-world-of-pandemic-16dg</link>
      <guid>https://dev.to/colbyfayock/how-to-build-tech-communities-in-a-world-of-pandemic-16dg</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uLAHTtrt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/07/building-tech-communities.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uLAHTtrt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/07/building-tech-communities.jpg" alt="How to Build Tech Communities in a World of Pandemic" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The global pandemic has had widespread effects, not just in how we go to work or go out to eat, but how we socialize and network in our local tech communities.&lt;/p&gt;

&lt;p&gt;What impact does this have on our journeys and what can we do to make the best out of the current climate?&lt;/p&gt;

&lt;h2&gt;
  
  
  Living in a world of a pandemic
&lt;/h2&gt;

&lt;p&gt;Most of our lives have rapidly changed. While many in the tech community are fortunate enough to be able to work from home, the pandemic has changed how we communicate and socialize.&lt;/p&gt;

&lt;p&gt;Where previously we were able to enjoy a bite to eat at a restaurant, now we don't have that option and have to order takeout. Where we once were able to go to a monthly meetup and hear about tech over some free pizza, now we watch virtually as we… pay for our own pizza.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does this impact us as developers?
&lt;/h2&gt;

&lt;p&gt;While it’s challenging not to be able to go meet people in person at your local meetup, being quarantined has different impacts on different people.&lt;/p&gt;

&lt;p&gt;Meetups and conferences are fun. Being able to communicate with others and build real relationships with others helps us all grow both personally and professionally. It’s a good way to network and make a friend at the same time.&lt;/p&gt;

&lt;p&gt;Moving these events online means that personal connection won’t be the same. While a meetup would traditionally have some social time, now we get a one-way feed of the speaker’s talk with maybe an opportunity to hang out with people in the chat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where does that leave us?
&lt;/h2&gt;

&lt;p&gt;This can be hard to cope with, but it doesn’t impact everyone the same. Some of us might be able to comfortably go meet others at a local meet up, but some of us, like myself, struggle with in-person events. Anxiety is real and it can hold us back and prevent us from being ourselves.&lt;/p&gt;

&lt;p&gt;The fact that these events are now online opens these communities up to people who might have been too uncomfortable to attend an in-person event. Instead of feeling too shy to chat during the social time, we’re still able to hold realtime conversations, but over Slack or Discord.&lt;/p&gt;

&lt;h2&gt;
  
  
  What can we do to take advantage of our circumstances?
&lt;/h2&gt;

&lt;p&gt;There’s two main perspectives to consider when figuring out what we can do to empower people in our communities — the organizers and the attendees.&lt;/p&gt;

&lt;p&gt;As organizers, we should try to provide more opportunities for others to be social, whether that’s by maintaining a community through tools like Slack or Discord or inviting others to communicate during the event.&lt;/p&gt;

&lt;p&gt;While some online meetups open up for questions or interact with the chat, some don’t, and it it feels simply like watching a video on Youtube.&lt;/p&gt;

&lt;p&gt;As attendees, we should try to take advantage of events being held online by trying to communicate more with our peers. While it might be challenging to chat in person, sending a DM or sharing your thoughts through chat is a lower barrier of entry.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can this help us in the long term?
&lt;/h2&gt;

&lt;p&gt;Being more social can help us in a variety of ways — it helps us grow individually and helps us learn from other’s experience. But it can also help us professionally.&lt;/p&gt;

&lt;p&gt;The fact of the matter is - if you don’t know anyone, you’re just another person on the list of thousands of applicants. Whether you meet someone at a meetup or had a quick chat with them in a Twitter DM, there’s a personal connection.&lt;/p&gt;

&lt;p&gt;Use that personal connection to your advantage. That might be the difference between you and another candidate who hasn’t said anything at all. It might mean more opportunities in the long run when that person thinks of you for their next job opening.&lt;/p&gt;

&lt;p&gt;But also, it can mean a new friend.  It won’t always open the door to that new job, but shared experiences and common interests bring people together, and that connection brings value.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying these lessons to the future
&lt;/h2&gt;

&lt;p&gt;Overall, we as a community need to continue to come together and help each other grow. The more we support each other, the more we can provide value that impacts the world.&lt;/p&gt;

&lt;p&gt;When the virus one day subsides and we begin to meet back in person, let’s not forget the lessons we learned about community building.&lt;/p&gt;

&lt;p&gt;Let’s make sure we continue to make everyone feel welcome and able to be involved, whether they’re the ones in the physical audience or the ones hanging out on the livestream.&lt;/p&gt;

&lt;p&gt;Make sure to engage with both audiences and let the virtual attendees feel like they're included in the conversation. Answer the questions that they're sending in chat. Pull them up on the screen to ask a question.&lt;/p&gt;

&lt;p&gt;We’re all in this together, let’s continue to build the best community we can.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;🐦 Follow Me On Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/colbyfayock" rel="noopener noreferrer"&gt;📽️ Subscribe To My Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.colbyfayock.com/newsletter/" rel="noopener noreferrer"&gt;✉️ Sign Up For My Newsletter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>communitybuilding</category>
      <category>networking</category>
      <category>selfimprovement</category>
    </item>
    <item>
      <title>What is Tailwind CSS and How Can I Add it to my Website or React App?</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Fri, 19 Jun 2020 13:19:59 +0000</pubDate>
      <link>https://dev.to/colbyfayock/what-is-tailwind-css-and-how-can-i-add-it-to-my-website-or-react-app-38c1</link>
      <guid>https://dev.to/colbyfayock/what-is-tailwind-css-and-how-can-i-add-it-to-my-website-or-react-app-38c1</guid>
      <description>&lt;p&gt;CSS is a technology that can be your best or worst friend. While it's incredibly flexible and can produce what seems like magic, without the proper care and attention, it can become hard to manage like any other code.&lt;/p&gt;

&lt;p&gt;How can Tailwind CSS help us to take control of our styles?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  What is Tailwind?
&lt;/li&gt;
&lt;li&gt;  So what makes Tailwind great?
&lt;/li&gt;
&lt;li&gt;  Part 1: Adding Tailwind CSS to a static HTML page
&lt;/li&gt;
&lt;li&gt;  Part 2: Adding Tailwind CSS to a React app
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/7KeZcRMltP0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Tailwind?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt; is a "utility-first" CSS framework that provides a deep catalog of CSS classes and tools that lets you easily get started styling your website or application.&lt;/p&gt;

&lt;p&gt;The underlying goal is that as you're building your project, you don't need to deal with cascading styles and worrying about how to override that 10-selector pileup that's been haunting your app for the last 2 years.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what makes Tailwind great?
&lt;/h2&gt;

&lt;p&gt;Taildwind's solution is to provide a wide variety of CSS classes that each have their own focused use. Instead of a class called &lt;code&gt;.btn&lt;/code&gt; that is created with a bunch of CSS attributes directly, in Tailwind, you would either apply a bunch of classes like &lt;code&gt;bg-blue-500 py-2 px-4 rounded&lt;/code&gt; to the button element or build a &lt;code&gt;.btn&lt;/code&gt; class by &lt;a href="https://tailwindcss.com/docs/functions-and-directives/#apply" rel="noopener noreferrer"&gt;applying&lt;/a&gt; those utility class to that selector.&lt;/p&gt;

&lt;p&gt;While Tailwind has a lot more going for it, we're going to focus on these basics for this tutorial, so let's dig in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Adding Tailwind CSS to a static HTML page
&lt;/h2&gt;

&lt;p&gt;We're going to start off by applying Tailwind CSS straight to a static HTML page. The hope is that by focusing on Tailwind and not the app, we can get a better understanding of what's actually happening with the framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Creating a new page
&lt;/h3&gt;

&lt;p&gt;You can get started by simply creating a new HTML file. For the content, you can use whatever you want, but I'm going to use &lt;a href="http://fillerama.io/" rel="noopener noreferrer"&gt;fillerama.io&lt;/a&gt; so the filler content is a bit more fun.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxgdaa4ef9vtzqk8zlnx1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxgdaa4ef9vtzqk8zlnx1.jpg" alt="New HTML page with content" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to simplify this step, you can just &lt;a href="https://github.com/colbyfayock/my-tailwind-static/commit/c7db11899c9cd193cdd666fd228cfaefe75623f2#diff-eacf331f0ffc35d4b482f1d15a887d3b" rel="noopener noreferrer"&gt;copy the file I created&lt;/a&gt; to get started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-tailwind-static/commit/c7db11899c9cd193cdd666fd228cfaefe75623f2" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Adding Tailwind CSS via CDN
&lt;/h3&gt;

&lt;p&gt;Tailwind typically recommends that you install through &lt;a href="https://www.npmjs.com/package/tailwindcss" rel="noopener noreferrer"&gt;npm&lt;/a&gt; to get the full functionality, but again, we're just trying to understand how this works first.&lt;/p&gt;

&lt;p&gt;So let's add a link to the CDN file in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of our document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you save and reload the page, the first thing you'll notice is that all of the styles were stripped!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fejp1vt6y692kjrlg8m8h.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fejp1vt6y692kjrlg8m8h.jpg" alt="HTML page with the Tailwind CSS base" width="800" height="194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is expected. Tailwind includes a set of &lt;a href="https://tailwindcss.com/docs/preflight" rel="noopener noreferrer"&gt;preflight styles&lt;/a&gt; to fix cross-browser inconsistencies. For one, they include the popular &lt;a href="https://github.com/necolas/normalize.css/" rel="noopener noreferrer"&gt;normalize.css&lt;/a&gt; which they build upon with their own styles.&lt;/p&gt;

&lt;p&gt;But we're going to learn how to use Tailwind to add back our styles and set things up how we want!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-tailwind-static/commit/b431b75cee0a03154a70b194b6dfcf028bc65942" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Using Tailwind CSS to add styles to your page
&lt;/h3&gt;

&lt;p&gt;Now that we have Tailwind installed, we've added the ability to make use of their huge library of utility classes that we'll now use to add styles back to our page.&lt;/p&gt;

&lt;p&gt;Let's start off by adding some margin to all of our paragraphs (&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;) and our list elements (&lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;). We can do this by adding the &lt;code&gt;.my-5&lt;/code&gt; class to each element like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p class="my-5"&amp;gt;
  Bender, quit destroying the universe! Yeah, I do that with my stupidness. I never loved you. Moving along...
  Belligerent and numerous.
&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class name follows a pattern that you'll notice with the rest of the utility classes -- &lt;code&gt;.my-5&lt;/code&gt; stands for margin (m) applied to the y-axis (y) with a value of 5 which in Tailwind's case, it uses &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units" rel="noopener noreferrer"&gt;rem&lt;/a&gt;, so the value is 5rem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fau6dm318k7b82oqryrjh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fau6dm318k7b82oqryrjh.jpg" alt="HTML page with basic paragraph styles" width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, let's make our headers look like actual headers. Starting with our &lt;code&gt;h1&lt;/code&gt; tag, let's add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h1 class="text-2xl font-bold mt-8 mb-5"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what's happening:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;text-2xl&lt;/code&gt;: set the text size (font-size) to 2xl. In Tailwind, that 2xl will equate to 1.5rem&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;font-bold&lt;/code&gt;: set the weight of the text (font-weight) to bold&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;mt-8&lt;/code&gt;: Similar to &lt;code&gt;my-5&lt;/code&gt;, this will set the margin top (t) to 8rem&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;mb-5&lt;/code&gt;: And this will set the margin bottom (b) to 5rem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8hjrpcspl7vg5l6l6tgg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F8hjrpcspl7vg5l6l6tgg.jpg" alt="HTML page with styled H1" width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With those classes added to the &lt;code&gt;h1&lt;/code&gt;, let's apply those same exact classes to the rest of our header elements, but as we go down the list, reduce the size of the font size, so it will look like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  h2: &lt;code&gt;text-xl&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  h3: &lt;code&gt;text-lg&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe7x41h32qi4ggbtgraeh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe7x41h32qi4ggbtgraeh.jpg" alt="HTML page with all headers styled" width="800" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's make our list elements look like lists. Starting with our unordered list (&lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;), let's add these classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ul class="list-disc list-inside my-5 pl-2"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what we're adding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;list-disc&lt;/code&gt;: set the list-style-stype to disc (the markers on each line item)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;list-inside&lt;/code&gt;: sets the position of the list markers using  relative to the list items and the list itself with list-style-position to inside&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;my-5&lt;/code&gt;: set the margin of the y axis to 5rem&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;pl-2&lt;/code&gt;: set the left padding to 2rem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then we can apply the exact same classes to our ordered list (&lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;), except instead of &lt;code&gt;list-disc&lt;/code&gt;, we want to change our style type to &lt;code&gt;list-decimal&lt;/code&gt;, so that we can see numbers given it's an ordered list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ol class="list-decimal list-inside my-5 pl-2"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we have our lists!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fco2mx3ifplvs8cauxu6x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fco2mx3ifplvs8cauxu6x.png" alt="HTML page with styled lists" width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, let's make our content a little easier to read by setting a max width and centering the content. On the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;body class="max-w-4xl mx-auto"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;/Note: Typically you wouldn't want to apply these classes to the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; itself, rather, you can wrap all of your content with a &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; tag, but since we're just trying to get an idea of how this works, we'll roll with this. Feel free to add the &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; tag with those classes instead if you prefer!/&lt;/p&gt;

&lt;p&gt;And with that, we have our page!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqp0h6724pb2g6f6qg70i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqp0h6724pb2g6f6qg70i.jpg" alt="HTML page with centered content" width="800" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-tailwind-static/commit/06fd719c98d17e2242b61ec2ab7034436c1c2ba6" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Adding a button and other components
&lt;/h3&gt;

&lt;p&gt;For the last part of our static example, let's add a button.&lt;/p&gt;

&lt;p&gt;The trick with Tailwind, is they intentionally don't provide pre-baked component classes with the idea being that likely people would need to override these components anyways to make them look how they wanted.&lt;/p&gt;

&lt;p&gt;So that means, we're going to have to create our own using the utility classes!&lt;/p&gt;

&lt;p&gt;First, let's add a new button. Somewhere on the page, add the following snippet. I'm going to add it right below the first paragraph (&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;) tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button&amp;gt;Party with Slurm!&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgh8qp1uwqka33su3ykpu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgh8qp1uwqka33su3ykpu.jpg" alt="HTML page with unstyled button" width="800" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice just like all of the other elements, that it's unstyled, however, if you try clicking it, you'll notice it still has the click actions. So let's make it look like a button.&lt;/p&gt;

&lt;p&gt;Let's add the following classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button class="text-white font-bold bg-purple-700 hover:bg-purple-800 py-2 px-4 rounded"&amp;gt;
  Party with Slurm!
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a breakdown of what's happening:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;text-white&lt;/code&gt;: we're setting our text color to white&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;font-bold&lt;/code&gt;: set the weight of the text to bold (font-weight)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;bg-purple-700&lt;/code&gt;: set the background color of the button to purple with a shade of 700. The 700 is relative to the other colors defined as purple, you can find these values on their &lt;a href="https://tailwindcss.com/docs/customizing-colors#default-color-palette" rel="noopener noreferrer"&gt;palette documentation page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;hover:bg-purple-800&lt;/code&gt;: when someone hovers over the button, set the background color to purple shade 800. Tailwind provides these helper classes that allow us to easily define interactive stiles with things like &lt;a href="https://tailwindcss.com/course/hover-focus-and-active-styles/" rel="noopener noreferrer"&gt;hover, focus, and active modifiers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;py-2&lt;/code&gt;: set the padding of the y-axis to 2rem&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;px-4&lt;/code&gt;: set the padding of the  x-axis to 4rem&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;rounded&lt;/code&gt;: round the corners of the element by setting the border radius. With tailwind, it sets the border-radius value to .25rem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And with all of that, we have our button!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv7yfzkhy722ka1eznpn1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fv7yfzkhy722ka1eznpn1.png" alt="HTML page with a styled button" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can apply this methodology to any other component that you'd like to build. Though it's a manual process, we'll find out how we can make this process easier when building in more dynamic projects like those based on React.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-tailwind-static/commit/09312336dce316a75e8007d6c935133490f16c25" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Adding Tailwind CSS to a React app
&lt;/h2&gt;

&lt;p&gt;For more of a real-world use case, we're going to add Tailwind CSS to an app created with &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html" rel="noopener noreferrer"&gt;Create React App&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First, we'll walk through the steps you need to take to add tailwind to your project using a fresh install of Create React App, then we'll use our content from our last example to recreate it in React.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Spinning up a new React app
&lt;/h3&gt;

&lt;p&gt;I'm not going to detail this step out too much. The gist is we'll bootstrap a new React app using Create React App.&lt;/p&gt;

&lt;p&gt;To get started, you can follow along &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html" rel="noopener noreferrer"&gt;with the directions&lt;/a&gt; from the official React documentation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://reactjs.org/docs/create-a-new-react-app.html" rel="noopener noreferrer"&gt;https://reactjs.org/docs/create-a-new-react-app.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And once you start your development server, you should now see an app!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxw22bt3r25w7f8j9hybf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxw22bt3r25w7f8j9hybf.png" alt="Create React App starting page" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, let's migrate all of our old content to our app. To do this, copy everything inside of the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag of our static example and paste it inside of the wrapper &lt;code&gt;&amp;lt;div className="App"&amp;gt;&lt;/code&gt; in the new React project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpd66n7qh1m4g1ik3ve4n.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpd66n7qh1m4g1ik3ve4n.jpg" alt="Migrating code to React app" width="800" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, change all &lt;code&gt;class="&lt;/code&gt; attributes from the content we pasted in to &lt;code&gt;className="&lt;/code&gt; so that it's using proper React attributes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3dtkdxz8q89kstc54ljj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3dtkdxz8q89kstc54ljj.jpg" alt="Fixing class attribute in content" width="800" height="107"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And lastly, replace the className &lt;code&gt;App&lt;/code&gt; on our wrapper &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; to the classes we used on our static &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbveqmfsnoqvgbpemoayv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbveqmfsnoqvgbpemoayv.jpg" alt="Adding wrapper styles to the app" width="800" height="103"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you save your changes and spin back up your server, it will look deceivingly okay.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffq13bujqorc4a85p05ws.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffq13bujqorc4a85p05ws.jpg" alt="React app with basic content" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React includes some basic styles itself, so while it looks okay, we're not actually using Tailwind yet. So let's get started by installing it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-tailwind-dynamic/commit/57993883c77739f71072bcc02ed2398543efc2fd" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Installing Tailwind in your React app
&lt;/h3&gt;

&lt;p&gt;There are a few steps we'll need to go through in order to get Tailwind up and running on our app. Make sure you follow these steps carefully to ensure it's properly configured.&lt;/p&gt;

&lt;p&gt;First, let's add our dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add tailwindcss postcss-cli autoprefixer
# or
npm install tailwindcss postcss-cli autoprefixer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://tailwindcss.com/docs/installation#4-process-your-css-with-tailwind" rel="noopener noreferrer"&gt;Per Tailwind's documentation&lt;/a&gt;, we need to be able to process our styles so that they can be properly added to our pipeline. So in the above, we're adding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;tailwindcss&lt;/a&gt;: the core Tailwind package&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/postcss/postcss" rel="noopener noreferrer"&gt;postcss-cli&lt;/a&gt;: Create React App already uses postcss, but we need to configure Tailwind to be part of that build process and run it's own processing&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/postcss/autoprefixer" rel="noopener noreferrer"&gt;autoprefixer&lt;/a&gt;: Tailwind doesn't include vendor prefixes, so we want to add autoprefixer to handle this for us. This runs as part of our postcss configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're also going to add two dev dependencies that make it easier to work with our code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add concurrently chokidar-cli -D
# or
npm install concurrently chokidar-cli --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/kimmobrunfeldt/concurrently" rel="noopener noreferrer"&gt;concurrently&lt;/a&gt;: a package that lets us set up the ability to run multiple commands at once. This is helpful since we'll need to watch both the styles and React app itself.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/kimmobrunfeldt/chokidar-cli" rel="noopener noreferrer"&gt;chokidar-cli&lt;/a&gt;: let's us watch files and run a command when changed. We'll use this to watch our CSS file and run the build process of the CSS on cahnge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, let's configure postcss, so create a new file in the root of your project called &lt;code&gt;postcss.config.js&lt;/code&gt; and include the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Inside postcss.config.js
module.exports = {
    plugins: [
        require('tailwindcss'),
        require('autoprefixer')
    ],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will add the Tailwindcss and Autoprefixer plugins to our postcss config.&lt;/p&gt;

&lt;p&gt;With our configuration, we need to include it as part of the build and watch processes. Inside &lt;code&gt;package.json&lt;/code&gt;, add the following to definitions to your &lt;code&gt;scripts&lt;/code&gt; property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"build:css": "tailwind build src/App.css -o src/index.css",
"watch:css": "chokidar 'src/App.css' -c 'npm run build:css'",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, modify the &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; scripts to now include those commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"start": "concurrently -n Tailwind,React 'npm run watch:css' 'react-scripts start'",
"build": "npm run build:css &amp;amp;&amp;amp; react-scripts build",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our configuration ready to go, let's try our styles back to where they were when we left off from the static example.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;App.css&lt;/code&gt; file, replace the entire content with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@tailwind base;
@tailwind components;
@tailwind utilities;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is going to import Tailwind's base styles, components, and utility classes that allow Tailwind to work as you would expect it to.&lt;/p&gt;

&lt;p&gt;We can also remove the &lt;code&gt;App.css&lt;/code&gt; import from our &lt;code&gt;App.js&lt;/code&gt; file because it's now getting injected directly into our &lt;code&gt;index.css&lt;/code&gt; file. So remove this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import './App.css';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you're done, you can start back up your development server! If it was already started, make sure to restart it so all of the configuration changes take effect.&lt;/p&gt;

&lt;p&gt;And now the page should look exactly like it did in our static example!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fti4lmnbk0hbw2uyoocjq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fti4lmnbk0hbw2uyoocjq.png" alt="React app with content styled" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-tailwind-dynamic/commit/5f50cc218ef58f469dad7f09bdad31f36b58a896" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Creating a new button component class with Tailwind
&lt;/h3&gt;

&lt;p&gt;Tailwind doesn't ship with prebaked component classes, but it does make it easy to create them!&lt;/p&gt;

&lt;p&gt;We're going to use our button that we already created as an example of creating a new component. We'll create a new class &lt;code&gt;btn&lt;/code&gt; as well as a color modifier &lt;code&gt;btn-purple&lt;/code&gt; to accomplish this.&lt;/p&gt;

&lt;p&gt;The first thing we'll want to do is open up our App.css file where we'll create our new class. Inside that file, let's add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.btn {
  @apply font-bold py-2 px-4 rounded;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you remember from our HTML, we're already including those same classes to our &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element.  Tailwind let's us "apply" or include the styles that make up these utility classes to another class, in this case, the &lt;code&gt;.btn&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;And now that we're creating that class, let's apply it to our button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button className="btn text-white bg-purple-700 hover:bg-purple-800"&amp;gt;
  Party with Slurm!
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if we open up our page, we can see our button still looks the same. If we inspect the element, we can see our new &lt;code&gt;.btn&lt;/code&gt; class generated with those styles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu0obhyela61kgkcmtfh7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu0obhyela61kgkcmtfh7.jpg" alt=".btn class in a React app with Tailwind" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, let's create a color modifier. Similar to what we just did, we're going to add the following rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.btn-purple {
  @apply bg-purple-700 text-white;
}

.btn-purple:hover {
  @apply bg-purple-800;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we're adding our background color and our text color to our button class. We're also applying a darker button color when someone hovers over the button.&lt;/p&gt;

&lt;p&gt;We'll also want to update our HTML button to include our new class and remove the ones we just applied:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button className="btn btn-purple"&amp;gt;
  Party with Slurm!
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that change, we can still see that nothing has changed and we have our new button class!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcgkbg7uknhj2if46menw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcgkbg7uknhj2if46menw.png" alt="Styled button in React with Tailwind" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-tailwind-dynamic/commit/7a76e8a4583b0a4c523ea902d73e889c7b86f437" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying these concepts to more components
&lt;/h2&gt;

&lt;p&gt;Through this walkthrough, we learned how to create a new component class using the Tailwind apply directive. This allowed us to create reusable classes that represent a component like a button.&lt;/p&gt;

&lt;p&gt;We can apply this to any number of components in our design system. For instance, if we wanted to always show our lists the way we set them up here, we could create a &lt;code&gt;.list-ul&lt;/code&gt; class that represented an unordered list with the Tailwind utilities &lt;code&gt;list-disc list-inside my-5 pl-2&lt;/code&gt; applied.&lt;/p&gt;

&lt;h2&gt;
  
  
  What tips and tricks do you like to use with Tailwind?
&lt;/h2&gt;

&lt;p&gt;Share with me on &lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>css</category>
      <category>frontend</category>
      <category>react</category>
    </item>
    <item>
      <title>Create your startup’s website on the Jamstack with Gatsby.js, TakeShape, and Netlify</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Thu, 14 May 2020 14:02:40 +0000</pubDate>
      <link>https://dev.to/takeshape/create-your-startup-s-website-on-the-jamstack-with-gatsby-js-takeshape-and-netlify-918</link>
      <guid>https://dev.to/takeshape/create-your-startup-s-website-on-the-jamstack-with-gatsby-js-takeshape-and-netlify-918</guid>
      <description>&lt;h2&gt;
  
  
  Use TakeShape's starter projects to get up and running in minutes with a Gatsby.js site on Netlify
&lt;/h2&gt;

&lt;p&gt;⚡️ &lt;a href="https://gatsby-starter-takeshape-startup.netlify.app/" rel="noopener noreferrer"&gt;See this sample project running live on Netlify&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Starting a new company is hard work. It takes considerable time, money, and energy to build a stellar team, develop an amazing product, and find customers for it. Creating your company’s website shouldn’t take away any resources from these important efforts, but it should still provide you with a foundation to grow.&lt;/p&gt;

&lt;p&gt;You can build a speedy, cost-effective, and maintainable static website for your business that still gives you editability and complex functionality as your business grows using the Jamstack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftnc822ycc8kzy34a34y1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftnc822ycc8kzy34a34y1.jpeg" alt="Jamstack - Javascript, APIs, &amp;amp; Markup Illustration by Colby Fayock" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Jamstack is a modern architecture where websites and applications are hosted statically and served from a content delivery network (CDN). This architecture provides a great deal of benefits, including &lt;a href="https://www.takeshape.io/articles/why-the-best-websites-are-static/" rel="noopener noreferrer"&gt;cost effectiveness, security, reliability, and scalability&lt;/a&gt;. While traditional websites require maintenance, scaling, and optimization in order to keep costs low, Jamstack sites are cheap and low-maintenance from the start.&lt;/p&gt;

&lt;p&gt;In this step-by-step guide, you’ll be introduced to the Jamstack as we walk through the process of creating a new site that runs on modern technologies with a reliable CMS to manage the content. And we’ll do it all in under 30 minutes!&lt;/p&gt;

&lt;h2&gt;
  
  
  What tools should I use to build, update, and serve my static Jamstack website?
&lt;/h2&gt;

&lt;p&gt;For our website, we're going to use three modern tools for building our site, managing the content, and hosting and deploying it to the cloud: Gatsby.js, TakeShape, and Netlify.&lt;/p&gt;

&lt;p&gt;If you haven’t heard of &lt;a href="https://www.gatsbyjs.org/" rel="noopener noreferrer"&gt;Gatsby.js&lt;/a&gt;, it’s a modern website framework that uses &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React.js&lt;/a&gt; and &lt;a href="https://graphql.org/" rel="noopener noreferrer"&gt;GraphQL&lt;/a&gt; to dynamically generate websites. It provides tools for developers to pull in many sources of content, including content from external services, and to output a website or app to a directory of static files and assets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.takeshape.io/" rel="noopener noreferrer"&gt;TakeShape&lt;/a&gt; is a content management system (CMS) with an intuitive user interface to add, edit, or delete content without the cost or maintenance overhead of a legacy CMS like Wordpress. Using TakeShape, all the members of your team can be productive right away, whether they’re a developer, content creator, or executive.&lt;/p&gt;

&lt;p&gt;Once you have a website or web application, you'll ultimately need to deploy it to a host so the world can visit it! That's where &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt; comes in: it builds your site, makes it available across a global CDN, and associates it with your custom domain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4dv3r1fsaudftpyxkpvn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4dv3r1fsaudftpyxkpvn.jpeg" alt="Netlify continuous integration and deployment" width="800" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Netlify’s continuous integration (CI) features make sure your site is always up to date. It integrates with Git clients, including Github and Gitlab, to automatically build and deploy new sites when your code changes. When you use TakeShape as your CMS, you’ll also have access to &lt;a href="https://www.takeshape.io/docs/webhooks/" rel="noopener noreferrer"&gt;webhooks&lt;/a&gt; that can &lt;a href="https://docs.netlify.com/configure-builds/build-hooks/" rel="noopener noreferrer"&gt;automatically trigger another build and deploy&lt;/a&gt; whenever changes occur to your content.&lt;/p&gt;

&lt;p&gt;Here’s how this all fits together: you’ll use Gatsby as the framework to code your site; TakeShape as the tool for editing and updating your content on the fly; and Netlify to host and continually rebuild your site as it's updated. Now, let’s get building!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Creating a new project in TakeShape
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating a new TakeShape project
&lt;/h3&gt;

&lt;p&gt;To get started with TakeShape, you'll first need to &lt;a href="https://app.takeshape.io/signup" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt; if you don’t have one already.&lt;/p&gt;

&lt;p&gt;TakeShape provides a number of ready to go example projects that will let you preconfigure a new project with an optimized, off-the-shelf solution. We'll use the Shape Startup Template to create and organize the kind of content that a young company needs.&lt;/p&gt;

&lt;p&gt;Under the Create a New Project header on the Projects page, select the Shape Startup Template and give it a name. For our walkthrough, we're going to use a fake company name TakeShape Startup, Co., but if you're building this for your company, this is where you should use your company's name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj3u9fzfu12kkg2lvxc3t.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj3u9fzfu12kkg2lvxc3t.jpeg" alt="Creating a new project in TakeShape" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting the Template and entering a name, click Create Project and you'll be dropped into your new project dashboard which includes a variety of sample content that we'll use to create our new website.&lt;/p&gt;

&lt;h3&gt;
  
  
  Save your Project ID and API Key
&lt;/h3&gt;

&lt;p&gt;When you land into your new project dashboard, you will also have a new project ID that we'll use to connect to the TakeShape API when creating our website with Gatsby.&lt;/p&gt;

&lt;p&gt;If you look at the URL of the page you're on, you'll see it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://app.takeshape.io/projects/[Project ID]/…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy and paste this ID to a secure place, like a local text file, where you can easily find it later.&lt;/p&gt;

&lt;p&gt;Then, select the dropdown arrow in the top left of the dashboard next to your project name and select &lt;strong&gt;API Keys&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuqagiu1zggl4bwcsx79y.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuqagiu1zggl4bwcsx79y.jpeg" alt="Navigating to API Keys" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;New API&lt;/strong&gt; Key button in the top right and you'll be asked to include a Title and Permissions for your key. You'll want to name the key something that makes sense that you'll remember when reviewing your keys. For our walkthrough, we'll use “Website” for our title.&lt;/p&gt;

&lt;p&gt;As for permissions, we can select &lt;strong&gt;Read&lt;/strong&gt; as we'll only be requesting the data, not modifying anything.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F89cu1rtypz7fb2bbjiug.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F89cu1rtypz7fb2bbjiug.jpeg" alt="Creating a new API Key" width="800" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, click &lt;strong&gt;Create API&lt;/strong&gt; Key in the top right and you'll be presented with a popup that includes your new API key. This is the only time you'll see this key!&lt;/p&gt;

&lt;p&gt;Copy this key and save it alongside your project ID—we'll need both of them later on to fetch our content from TakeShape with Gatsby. Once you have saved your key, you can click I Understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Creating a new site with Gatsby.js
&lt;/h2&gt;

&lt;p&gt;Next, we'll configure a new Gatsby project in our local development environment. You'll be expected to be able to use a terminal to run commands using npm or yarn.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: If you'd prefer to avoid local development, you could skip this section directly deploy the &lt;a href="https://github.com/colbyfayock/gatsby-starter-takeshape-startup" rel="noopener noreferrer"&gt;TakeShape Gatsby Starter&lt;/a&gt; to Netlify using the deploy button at the bottom of the page. This will create a new project in Netlify and Github repository for your project.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing the Gatsby CLI
&lt;/h3&gt;

&lt;p&gt;To set up our Gatsby project locally, we'll first need to install the &lt;a href="https://www.gatsbyjs.org/docs/gatsby-cli/#how-to-use-gatsby-cli" rel="noopener noreferrer"&gt;Gatsby CLI&lt;/a&gt;. In order to install the CLI, you can use your favorite NPM-based package manager and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; gatsby-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make sure it's installed, you can run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gatsby &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your install succeeded, it should show you how to use the Gatsby CLI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up a new TakeShape Gatsby project
&lt;/h3&gt;

&lt;p&gt;Inside your terminal, navigate to the directory where you want to create your project. Once there, run the following command, replacing &lt;code&gt;my-startup-project&lt;/code&gt; with a new folder name of your choice. This will create a new Gatsby project and install the necessary dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gatsby new my-startup-project https://github.com/colbyfayock/gatsby-starter-takeshape-startup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkkvp4u786x1o75ck4bgk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkkvp4u786x1o75ck4bgk.jpeg" alt="Installing a new project with Gatsby TakeShape Starter" width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the installation is complete, navigate to your project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-startup-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up TakeShape environment variables
&lt;/h3&gt;

&lt;p&gt;For this project to communicate securely with TakeShape, create a new file called .env in the project root and include the following content, replacing the placeholder values with the unique Project ID and API Key that we saved earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Inside .env&lt;/span&gt;
&lt;span class="nv"&gt;TAKESHAPE_PROJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[TakeShape Project ID]"&lt;/span&gt;
&lt;span class="nv"&gt;TAKESHAPE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[TakeShape API Access Key]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Starting up and building the project
&lt;/h3&gt;

&lt;p&gt;Once the environment variables are configured, we're ready to go! Gatsby gives us two commands, &lt;code&gt;develop&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Running &lt;code&gt;gatsby develop&lt;/code&gt; will start a development server where we can run our code locally, make changes as needed, and visit the local version of our site.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the other hand, &lt;code&gt;gatsby build&lt;/code&gt; will compile our code to static files, saving the output to the /public folder.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we've run the site locally and can confirm everything is working, we'll &lt;a href="https://help.github.com/en/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line" rel="noopener noreferrer"&gt;add these files to a new Github repository&lt;/a&gt; (but GitLab or Bitbucket would work, too!).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Hosting and deploying a website with Netlify
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Creating a Netlify account
&lt;/h3&gt;

&lt;p&gt;To host and deploy our new website, we'll need an account on Netlify. You can get started by signing up with a range of options including your Github, Gitlab, or Bitbucket account. If you'd prefer the traditional email route, you can use a regular email address as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting your Git repository to Netlify
&lt;/h3&gt;

&lt;p&gt;Once you're set up with Netlify, you'll want to connect your Git repository to your Netlify account. For this walkthrough, we're going to use Github, but Gitlab and Bitbucket should work similarly.&lt;/p&gt;

&lt;p&gt;When logging in, the first page you'll land on is the Sites page. Go ahead and click the New site from Git button in the top right of this page to get started.&lt;/p&gt;

&lt;p&gt;When you land on the Create a new site page, click the button that refers to your Git repository provider.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd5853lpc7y6ocse1sbr0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd5853lpc7y6ocse1sbr0.jpeg" alt="Creating a new website with your Git provider" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you click that, Netlify will open up a window from that Git provider (like Github), which will request permissions to your account. This is similar to using OAuth with a Google or Facebook account. Netlify requires you to connect your account so it can retrieve the repository to pull down the code in order to build and deploy it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fecirxqs4u55golp5g37r.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fecirxqs4u55golp5g37r.jpeg" alt="Connecting a repository to deploy a new website " width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you've integrated Git with your Netlify account, you should now see a list of your repositories. Now you can continue to select the repository of your new website at which point you'll be asked to configure the site.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fts2ruuuhxa59hy14m19n.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fts2ruuuhxa59hy14m19n.jpeg" alt="Configuring your project’s build settings" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since Netlify recognizes Gatsby sites, it does a great job at preconfiguring this for us. We should be set with “gatsby build” as our Build command and “public/” as our Publish directory. This means that Netlify will run the build command to compile our website and the output of that command will be available in the publish directory.&lt;/p&gt;

&lt;p&gt;But before we click the Deploy button we want to configure an advanced setting, which is our keys, so let’s first click Show advanced. Here, let’s add both of our environment variables &lt;code&gt;TAKESHAPE_PROJECT&lt;/code&gt; and &lt;code&gt;TAKESHAPE_API_KEY&lt;/code&gt; along with their respective values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi28ko1cnizjjdk9syovg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fi28ko1cnizjjdk9syovg.jpeg" alt="Configuring TakeShape environment variables when setting up Netlify" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, you can hit the &lt;strong&gt;Deploy&lt;/strong&gt; site button and Netlify will kick off a new build!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F33nqnc8yzgox45lpac1b.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F33nqnc8yzgox45lpac1b.jpeg" alt="Live website after successful deploy" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once completed, you should now be able to access your new website with the link at the top of the Overview page!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Configuring webhooks with TakeShape to build and deploy changes with Netlify
&lt;/h2&gt;

&lt;p&gt;Finally, if we're making changes to our content in TakeShape, we're going to want our website to rebuild and deploy so that we can automatically keep it updated. To do this, we can take advantage of webhooks to trigger new builds on Netlify.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a new webhook in Netlify
&lt;/h3&gt;

&lt;p&gt;To create a webhook in Netlify, first navigate to the Build &amp;amp; deploy page of your project settings and under the Continuous Deployment section, find Build hooks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc6kz5g9nfydaap58fsvu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fc6kz5g9nfydaap58fsvu.jpeg" alt="Creating a new Netlify webhook" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, click the &lt;strong&gt;Add build hook&lt;/strong&gt; button and add "TakeShape" or another value you will remember as the &lt;strong&gt;Name&lt;/strong&gt;. Unless you changed the primary branch of your builds, we'll want to leave the &lt;strong&gt;Branch to build&lt;/strong&gt; as "master". Then click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb9a7r71ey8q83gsgwoh1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb9a7r71ey8q83gsgwoh1.jpeg" alt="New Netlify webhook" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will create a new URL that we'll use to set up our webhook in TakeShape, so we'll want to save this value for later.&lt;/p&gt;

&lt;p&gt;Note: similar to an API key, you do not want to make this URL public. This provides the ability for builds to be triggered on your Netlify project. While this might not necessarily be able to cause major security issues, someone could potentially use this URL to run up your Netlify bill!&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding our Netlify webhook to TakeShape
&lt;/h3&gt;

&lt;p&gt;To start, we'll want to navigate to our TakeShape project, click the down arrow in the top left of the UI, and select Webhooks from the dropdown.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5wq1g2ldx0u20k56vleg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5wq1g2ldx0u20k56vleg.jpeg" alt="Alt Text" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once on the Webhooks page, click the &lt;strong&gt;Plus (+)&lt;/strong&gt; button to add a new webhook, enter in your Netlify webhook URL from before, and add the &lt;code&gt;Content: *&lt;/code&gt; resource. Check the boxes of all actions for all resources including &lt;strong&gt;Create&lt;/strong&gt;, &lt;strong&gt;Update&lt;/strong&gt;, and &lt;strong&gt;Delete&lt;/strong&gt;, and then finally click the &lt;strong&gt;Save&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frxhrjqhwliei3cvwb5rv.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frxhrjqhwliei3cvwb5rv.jpeg" alt="Updating TakeShape webhook settings" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing that the webhook works
&lt;/h3&gt;

&lt;p&gt;You should now have your TakeShape webhook set up, so let's test that it works.&lt;/p&gt;

&lt;p&gt;Navigate to the &lt;strong&gt;Homepage&lt;/strong&gt; section in your TakeShape project and make a change to the content. This can be as simple as adding an exclamation point (!) to the end of the &lt;strong&gt;Heading&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg3nrrdy4r12y9qvepijl.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg3nrrdy4r12y9qvepijl.jpeg" alt="Updating Homepage content in TakeShape" width="800" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you click the Save button, you can navigate back to your Netlify project and you should now see a new build triggered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1y43lkcr81y54tfrpmc6.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1y43lkcr81y54tfrpmc6.jpeg" alt="New build in Netlify triggered by TakeShape" width="800" height="95"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Shortly after, once that build is finished, you should now see your new change on your deployed website!&lt;/p&gt;

&lt;p&gt;Taking advantage of more features from TakeShape&lt;br&gt;
Want to learn about more exciting features TakeShape has to offer? Check out &lt;a href="https://www.takeshape.io/" rel="noopener noreferrer"&gt;takeshape.io&lt;/a&gt; where you can dig into the full range of options you have with the &lt;a href="https://www.takeshape.io/content-editor/" rel="noopener noreferrer"&gt;TakeShape Content Editor&lt;/a&gt; or how you can combine all of your API services into one, single GraphQL API with &lt;a href="https://www.takeshape.io/mesh/" rel="noopener noreferrer"&gt;TakeShape Mesh&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>jamstack</category>
      <category>gatsby</category>
    </item>
    <item>
      <title>How to Use Pure CSS to Create a Beautiful Loading Animation for your App</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Tue, 05 May 2020 14:45:00 +0000</pubDate>
      <link>https://dev.to/colbyfayock/how-to-use-pure-css-to-create-a-beautiful-loading-animation-for-your-app-5ece</link>
      <guid>https://dev.to/colbyfayock/how-to-use-pure-css-to-create-a-beautiful-loading-animation-for-your-app-5ece</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oFOmcEiv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/loading-animation.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oFOmcEiv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/loading-animation.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've been around the internet lately, you've most likely seen a nice subtle loading animation that fills page content before gracefully loading in.&lt;/p&gt;

&lt;p&gt;Some of the social giants like Facebook even use this approach to give page loading a better experience. How can we do that with just some simple CSS?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What are we going to build?&lt;/li&gt;
&lt;li&gt;Just want the snippet?&lt;/li&gt;
&lt;li&gt;Part 1: Creating our loading animation&lt;/li&gt;
&lt;li&gt;Part 2: Using our loading animation in a dynamic app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/auyZWWjXJCo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What are we going to build?
&lt;/h2&gt;

&lt;p&gt;We're going to create a loading animation using a CSS class that you can apply to pretty much any element you want (within reason).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MDWEX9aw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/loading-animation.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MDWEX9aw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/loading-animation.gif" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="210"&gt;&lt;/a&gt;Loading animation preview&lt;/p&gt;

&lt;p&gt;This gives you great flexibility to use it and makes the solution nice and simple with only CSS.&lt;/p&gt;

&lt;p&gt;While the snippet is pretty small and you could just copy and paste it, I'll walk you through what's happening and an example of using it dynamically when loading data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just want the snippet?
&lt;/h2&gt;

&lt;p&gt;You can grab it here!&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Do I need to know how to animate before this tutorial?
&lt;/h2&gt;

&lt;p&gt;No! We'll walk through in detail exactly what you need to do. In fact, the animation in this tutorial is relatively simple, so let's dig in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: Creating our loading animation
&lt;/h2&gt;

&lt;p&gt;This first part is going to focus on getting the loading animation together and seeing it on a static HTML website. The goal is to walk through actually creating the snippet. We'll only use HTML and CSS for this part.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Creating some sample content
&lt;/h3&gt;

&lt;p&gt;To get started, we'll want a little sample content. There's really no restrictions here, you can create this with basic HTML and CSS or you can add this to your Create React App!&lt;/p&gt;

&lt;p&gt;For the walk through, I'm going to use HTML and CSS with a few examples of content that will allow us to see this in effect.&lt;/p&gt;

&lt;p&gt;To get started, create a new HTML file. Inside that HTML file, fill it with some content that will give us the ability to play with our animation. I'm going to use &lt;a href="http://fillerama.io/" rel="noopener noreferrer"&gt;fillerama&lt;/a&gt; which uses lines from my favorite TV show &lt;a href="https://en.wikipedia.org/wiki/Futurama" rel="noopener noreferrer"&gt;Futurama&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6yf6FAW6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-website-fillerama.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6yf6FAW6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-website-fillerama.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="208"&gt;&lt;/a&gt;Static HTML &amp;amp; CSS webpage with content from fillerama.io&lt;/p&gt;

&lt;p&gt;If you're going to follow along with me, here's what my project looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-css-loading-animation-static
- index.html
- main.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-css-loading-animation-static/commit/9aa7925f7048fa1b73fef74d0d56380c29fc5d73" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Starting with a foundation loading class
&lt;/h3&gt;

&lt;p&gt;For our foundation, let's create a new CSS class. Inside our CSS file, let's add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.loading {
  background: #eceff1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that class, let's add it to a few or all of our elements. I added it to a few paragraphs, headings, and lists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;p class="loading"&amp;gt;For example...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kVAA3-Wn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-gray-background.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kVAA3-Wn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-gray-background.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="208"&gt;&lt;/a&gt;Static HTML &amp;amp; CSS webpage with a gray background for the content&lt;/p&gt;

&lt;p&gt;That gives us a basic background, but we'd probably want to hide that text. When it's loading, we won't have that text yet, so most likely we would want to use filler text or a fixed height. Either way, we can set the color to transparent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.loading {
  color: transparent;
  background: #eceff1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G_h4RwKU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-gray-background-hidden-text.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G_h4RwKU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-gray-background-hidden-text.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="278"&gt;&lt;/a&gt;Static HTML &amp;amp; CSS webpage with a gray background and transparent color for the content&lt;/p&gt;

&lt;p&gt;If you notice with list elements, whether you apply the class to the top level list element (&lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;) vs the list item itself (&lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;), it looks like one big block. If we add a little margin to the bottom of all list elements, we can see a different in how they display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;li {
  margin-bottom: .5em;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HT7cdcBi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-gray-background-different-lists.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HT7cdcBi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-gray-background-different-lists.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="240"&gt;&lt;/a&gt;Style difference between applying to the top level list or the list items&lt;/p&gt;

&lt;p&gt;And now it's starting to come together, but it kind of just looks like placeholders. So let's animate this to look like it's actually loading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-css-loading-animation-static/commit/f68cdef36be11311a5cc11a1d39e52ea7e7bb48d" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Styling and animating our loading class
&lt;/h3&gt;

&lt;p&gt;Before actually animating our class, we need something to animate, so let's add a gradient to our &lt;code&gt;.loading&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.loading {
  color: transparent;
  background: linear-gradient(100deg, #eceff1 30%, #f6f7f8 50%, #eceff1 70%);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is saying that we want a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient" rel="noopener noreferrer"&gt;linear gradient&lt;/a&gt; that's tilted at 100 degrees, where we start with &lt;code&gt;#eceff1&lt;/code&gt; and fade to &lt;code&gt;#f6f7f8&lt;/code&gt; at 30% and back to &lt;code&gt;#eceff1&lt;/code&gt; at 70%;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pMDRPZEq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-gray-background-subtle-gradient.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pMDRPZEq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-gray-background-subtle-gradient.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="240"&gt;&lt;/a&gt;Subtle gradient background that might look like a glare&lt;/p&gt;

&lt;p&gt;It's hard to see initially when it's still, it might just look like a glare on your computer! If you'd like to see it before moving on, feel free to play with the colors above to see the gradient.&lt;/p&gt;

&lt;p&gt;Now that we have something to animate, we'll first need to create a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes" rel="noopener noreferrer"&gt;keyframes&lt;/a&gt; rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@keyframes loading {
  0% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0 50%;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This rule when applied will change the background position from starting at 100% of the x-axis to 0% of the x-axis.&lt;/p&gt;

&lt;p&gt;With the rule, we can add our &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations" rel="noopener noreferrer"&gt;animation&lt;/a&gt; property to our &lt;code&gt;.loading&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.loading {
  color: transparent;
  background: linear-gradient(100deg, #eceff1 30%, #f6f7f8 50%, #eceff1 70%);
  animation: loading 1.2s ease-in-out infinite;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our animation line is setting the keyframe to &lt;code&gt;loading&lt;/code&gt;, telling it to last for 1.2 seconds, setting the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function" rel="noopener noreferrer"&gt;timing function&lt;/a&gt; to &lt;code&gt;ease-in-out&lt;/code&gt; to make it smooth, and tell it to loop forever with &lt;code&gt;infinite&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pMDRPZEq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-gray-background-subtle-gradient.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pMDRPZEq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-gray-background-subtle-gradient.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="240"&gt;&lt;/a&gt;No change – it's not animating&lt;/p&gt;

&lt;p&gt;If you notice though after saving that, it's still not doing anything. The reason for this is we're setting our gradient from one end of the DOM element to the other, so there's nowhere to move!&lt;/p&gt;

&lt;p&gt;So let's try also setting a &lt;code&gt;background-size&lt;/code&gt; on our &lt;code&gt;.loading&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.loading {
  color: transparent;
  background: linear-gradient(100deg, #eceff1 30%, #f6f7f8 50%, #eceff1 70%);
  background-size: 400%;
  animation: loading 1.2s ease-in-out infinite;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, since our background expands beyond our DOM element (you can't see that part), it has some space to animate with and we get our animation!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xigrhcf0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-loading-animation.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xigrhcf0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/static-html-css-loading-animation.gif" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="314"&gt;&lt;/a&gt;Our loading animation!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-css-loading-animation-static/commit/bc4b5ec955a0906fea032edbbaf90f037f76c91b" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Using our loading animation in a dynamic app
&lt;/h2&gt;

&lt;p&gt;Now that we have our loading animation, let's put it into action with a basic example where we fake a loading state.&lt;/p&gt;

&lt;p&gt;The trick with actually using this is typically we don't have the actual content available, so in most cases, we have to fake it.&lt;/p&gt;

&lt;p&gt;To show you how we can do this, we're going to build a simple &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; app with &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Creating an example React app with Next.js
&lt;/h3&gt;

&lt;p&gt;Navigate to the directory you want to create your new project in and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn create next-app
# or
npm init next-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will prompt you with some options, particularly a name which will determine the directory the project is created in and the type of project. I'm using &lt;code&gt;my-css-loading-animation-dynamic&lt;/code&gt; and the "Default Starter App".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S5wJ_n3k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/nextjs-new-project.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S5wJ_n3k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/nextjs-new-project.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="191"&gt;&lt;/a&gt;Creating a new project with Next.js&lt;/p&gt;

&lt;p&gt;Once installed, navigate into your new directory and start up your development server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd [directory]
yarn dev
# or 
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O0tBkxYx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/nextjs-starting-dev-server.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O0tBkxYx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/nextjs-starting-dev-server.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="187"&gt;&lt;/a&gt;Starting development server with Next.js&lt;/p&gt;

&lt;p&gt;Next, let's replace the content in our &lt;code&gt;pages/index.js&lt;/code&gt; file. I'm going to derive the content from the previous example, but we'll create it similar to how we might expect it to come from an API. First, let's add our  content as an object above our return statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const content = {
  header: `So, how 'bout them Knicks?`,
  intro: `What are their names? I'm Santa Claus! This opera's as lousy as it is brilliant! Your lyrics lack subtlety. You can't just have your characters announce how they feel. That makes me feel angry! Good news, everyone! I've taught the toaster to feel love!`,
  list: [
    `Yes! In your face, Gandhi!`,
    `So I really am important? How I feel when I'm drunk is correct?`,
    `Who are those horrible orange men?`
  ]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To display that content, inside &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;, let's replace the content with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;main&amp;gt;
  &amp;lt;h1&amp;gt;{ content.header }&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;{ content.intro }&amp;lt;/p&amp;gt;
  &amp;lt;ul&amp;gt;
    { content.list.map((item, i) =&amp;gt; {
      return (
        &amp;lt;li key={i}&amp;gt;{ item }&amp;lt;/li&amp;gt;
      )
    })}
  &amp;lt;/ul&amp;gt;
&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for the styles, you can copy and paste everything from our Part 1 &lt;code&gt;main.css&lt;/code&gt; file into the &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tags at the bottom of our index page. That will leave us with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VEesh30w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/basic-content-with-nextjs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VEesh30w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/basic-content-with-nextjs.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="158"&gt;&lt;/a&gt;Basic content with Next.js&lt;/p&gt;

&lt;p&gt;With that, we should be back to a similar point we finished at in Part 1 except we're not actively using any of the loading animations yet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-css-loading-animation-dynamic/commit/365e081522ec07b1754bf360a95b0bc373476c95" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Faking loading data from an API
&lt;/h3&gt;

&lt;p&gt;The example we're working with is pretty simple. You'd probably see this coming pre-generated statically, but this helps us create a realistic demo that we can test our loading animation with.&lt;/p&gt;

&lt;p&gt;To fake our loading state, we're going to use React's &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useEffect&lt;/code&gt;, and an old fashioned &lt;code&gt;setTimeout&lt;/code&gt; to preload some "loading" content, and after the &lt;code&gt;setTimeout&lt;/code&gt; finishes, update that content with our actual data. In the meantime, we'll know that we're in a loading state with a separate instance of &lt;code&gt;useState&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, we need to import our dependencies. At the top of our &lt;code&gt;pages/index.js&lt;/code&gt; file, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState, useEffect } from 'react';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above our &lt;code&gt;content&lt;/code&gt; object, let's add some state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [loadingState, updateLoadingState] = useState(true);
const [contentState, updateContentState] = useState({})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in our content, we can update the instances to use that state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h1&amp;gt;{ contentState.header }&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;{ contentState.intro }&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
  { contentState.list.map((item, i) =&amp;gt; {
    return (
      &amp;lt;li key={i}&amp;gt;{ item }&amp;lt;/li&amp;gt;
    )
  })}
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you save and load that, you'll first notice we get an error because our &lt;code&gt;list&lt;/code&gt; property doesn't exist on our &lt;code&gt;contentState&lt;/code&gt;, so we can first fix that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ Array.isArray(contentState.list) &amp;amp;&amp;amp; contentState.list.map((item, i) =&amp;gt; {
  return (
    &amp;lt;li key={i}&amp;gt;{ item }&amp;lt;/li&amp;gt;
  )
})}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And after that's ready, let's add our &lt;code&gt;setTimeout&lt;/code&gt; inside of a &lt;code&gt;useEffect&lt;/code&gt; hook to simulate our data loading. Add this under our &lt;code&gt;content&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
  setTimeout(() =&amp;gt; {
    updateContentState(content);
    updateLoadingState(false)
  }, 2000);
}, [])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you save and open up your browser, you'll notice that for 2 seconds you don't have any content and then it loads in, basically simulating loading that data asynchronously.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-css-loading-animation-dynamic/commit/f0cada8d696ffe3e983f5efc03dc9d75a2245fe1" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Adding our loading animation
&lt;/h3&gt;

&lt;p&gt;Now we can finally add our loading animation. So to do this, we're going to use our loading state we set up using &lt;code&gt;useState&lt;/code&gt; and if the content is loading, add our &lt;code&gt;.loading&lt;/code&gt;  class to our elements.&lt;/p&gt;

&lt;p&gt;Before we do that, instead of individually adding this class to each item in the DOM, it might make more sense to do so using CSS and adding the class to the parent, so let's do that first.&lt;/p&gt;

&lt;p&gt;First, update the &lt;code&gt;.loading&lt;/code&gt; class to target our elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.loading h1,
.loading p,
.loading li {
  color: transparent;
  background: linear-gradient(100deg, #eceff1 30%, #f6f7f8 50%, #eceff1 70%);
  background-size: 400%;
  animation: loading 1.2s ease-in-out infinite;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can dynamically add our class to our &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;main className={loadingState ? 'loading' : ''}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: if you use &lt;a href="https://sass-lang.com/" rel="noopener noreferrer"&gt;Sass&lt;/a&gt;,  you can manage your loading styles by &lt;a href="https://sass-lang.com/documentation/at-rules/extend" rel="noopener noreferrer"&gt;extending&lt;/a&gt; the &lt;code&gt;.loading&lt;/code&gt; class in the instances you want to use it or create a &lt;a href="https://sass-lang.com/documentation/style-rules/placeholder-selectors" rel="noopener noreferrer"&gt;placeholder&lt;/a&gt; and extend that!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And if you refresh the page, you'll notice it's still just a blank page for 2 seconds!&lt;/p&gt;

&lt;p&gt;The issue, is when we load our content, nothing exists inside of our tags that can that would allow the line-height of the elements to give it a height.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kh1vTfyw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/html-css-collapsed-content.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kh1vTfyw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/html-css-collapsed-content.jpg" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="158"&gt;&lt;/a&gt;No height when there's no content&lt;/p&gt;

&lt;p&gt;But we can fix that! Because our &lt;code&gt;.loading&lt;/code&gt; class sets our text to transparent, we can simply add the word &lt;code&gt;Loading&lt;/code&gt; for each piece of content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [contentState, updateContentState] = useState({
  header: 'Loading',
  intro: 'Loading',
  list: [
    'Loading',
    'Loading',
    'Loading'
  ]
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: We can't use an empty space here because that alone won't provide us with a height when rendered in the DOM.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And once you save and reload the page, our first 2 seconds will have a loading state that reflects our content!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mrb-C4GO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/html-css-loading-animation-1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mrb-C4GO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.freecodecamp.org/news/content/images/2020/05/html-css-loading-animation-1.gif" alt="How to Use Pure CSS to Create a Beautiful Loading Animation for your App" width="800" height="156"&gt;&lt;/a&gt;HTML &amp;amp; CSS loading animation&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-css-loading-animation-dynamic/commit/5b7b1c40d1eebf97f65c966bb771a5f6787073ea" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Some additional thoughts
&lt;/h2&gt;

&lt;p&gt;This technique can be used pretty broadly. Being a CSS class makes it nice and easy to add where every you want.&lt;/p&gt;

&lt;p&gt;If you're not a fan of setting the &lt;code&gt;Loading&lt;/code&gt; text for the loading state, another option is to set a fixed height. The only issue with that is it requires more maintenance for tweaking the CSS to match what the content loading in will look like.&lt;/p&gt;

&lt;p&gt;Additionally, this won't be perfect. More often than not, you won't know exactly how much copy you have on a page. The goal is to simulate and hint that there will be content and that it's currently loading.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's your favorite loading animation?
&lt;/h2&gt;

&lt;p&gt;Let me know on &lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;🐦 Follow Me On Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/colbyfayock" rel="noopener noreferrer"&gt;📽️ Subscribe To My Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.colbyfayock.com/newsletter/" rel="noopener noreferrer"&gt;✉️ Sign Up For My Newsletter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
      <category>css3</category>
      <category>purecss</category>
      <category>html</category>
    </item>
    <item>
      <title>What is the JAMstack and how do I get started?</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Tue, 05 May 2020 12:36:52 +0000</pubDate>
      <link>https://dev.to/colbyfayock/what-is-the-jamstack-and-how-do-i-get-started-4175</link>
      <guid>https://dev.to/colbyfayock/what-is-the-jamstack-and-how-do-i-get-started-4175</guid>
      <description>&lt;p&gt;JAMstack sites are all the rage right now in the web dev world. And rightfully so! But what exactly is it and how can we all take advantage of its benefits?&lt;/p&gt;

&lt;h2&gt;
  
  
  What is this JAMstack?
&lt;/h2&gt;

&lt;p&gt;To start, &lt;a href="https://jamstack.org/" rel="noopener noreferrer"&gt;JAMstack&lt;/a&gt; is a software architecture and philosophy that adheres to the following components: Javascript, APIs, and Markup.&lt;/p&gt;

&lt;p&gt;If this sounds familiar, it's because it is! That React app that you compile down with &lt;a href="https://webpack.js.org/" rel="noopener noreferrer"&gt;Webpack&lt;/a&gt; and ultimately serve from &lt;a href="https://aws.amazon.com/s3/" rel="noopener noreferrer"&gt;S3&lt;/a&gt;? Yup, that's a JAMstack app. That simple HTML file that has no JavaScript and literally doesn't do anything dynamic? Yup, that's also a JAMstack app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6yu8ck8z88goj4421gj1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6yu8ck8z88goj4421gj1.gif" alt="Bill and Ted play air guitars" width="480" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  That's not to be confused with serverless
&lt;/h2&gt;

&lt;p&gt;If you're coming more from the cloud side of things (think &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt;, &lt;a href="https://cloud.google.com/" rel="noopener noreferrer"&gt;GCP&lt;/a&gt;, &lt;a href="https://azure.microsoft.com/" rel="noopener noreferrer"&gt;Azure&lt;/a&gt;), you might be inclined to think of &lt;a href="https://serverless-stack.com/chapters/what-is-serverless.html" rel="noopener noreferrer"&gt;serverless&lt;/a&gt; and JAMstack as the same thing. Granted they have similarities in the philosophy of how resources are managed, such as hosting a site on S3. But a JAMstack app is not always going to be a serverless app.&lt;/p&gt;

&lt;p&gt;Consider an app hosted in static storage on the cloud provider of your choice. Yes, you might be serving the app in a serverless way, but you might be dealing with an API that utilizes Wordpress or Rails, both of which are certainly not serverless.&lt;/p&gt;

&lt;p&gt;Combining these philosophies can go a long way, but they shouldn't be confused as the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes up the JAMstack?
&lt;/h2&gt;

&lt;p&gt;Back to the JAMstack: it's typically comprised of 3 components: Javascript, APIs, and Markup. Its &lt;a href="https://snipcart.com/blog/jamstack" rel="noopener noreferrer"&gt;history stems&lt;/a&gt; from growing the term "static site" into something more meaningful (and marketable). So while ultimately a static site is the end result, it's blown up to include first class tooling for every step of the way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz3plpm6ww3b8jhpicbh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fz3plpm6ww3b8jhpicbh1.png" alt="JAMstack breakdown" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While there aren't any specific set of tools that you need to use, or any tools at all beyond simple HTML, there are great examples of what can make up each part of the stack. Let's dive in a little bit to each component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Javascript
&lt;/h3&gt;

&lt;p&gt;The component that's probably done the most work to popularize the JAMstack is Javascript. Our favorite browser language allows us to provide all of the dynamic and interactive bits that we might not have if we're serving plain HTML without it.&lt;/p&gt;

&lt;p&gt;This is where a lot of times you'll see UI frameworks like &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt;, &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;, and newcomers like &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; come into play.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb1t0rqwxhdkiz6rutte4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb1t0rqwxhdkiz6rutte4.jpg" alt="" width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They make building apps simpler and more organized by providing component APIs and tooling that compile down to a simple HTML file (or a bunch of them).&lt;/p&gt;

&lt;p&gt;Those HTML files include a group of assets like images, CSS, and the actual JS that ultimately get served to a browser via your favorite CDN (content delivery network).&lt;/p&gt;

&lt;h3&gt;
  
  
  APIs
&lt;/h3&gt;

&lt;p&gt;Utilizing the strengths of APIs is core to how you make a JAMstack app dynamic. Whether it's authentication or search, your application will use Javascript to make an HTTP request to another provider which will ultimately enhance the experience in one form or another.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.gatsbyjs.org/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt; coined the phrase "&lt;a href="https://www.gatsbyjs.org/blog/2018-10-04-journey-to-the-content-mesh/" rel="noopener noreferrer"&gt;content mesh&lt;/a&gt;" that does a pretty good job at describing the possibilities here.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4953sgekf0zrm1v25klj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4953sgekf0zrm1v25klj.jpg" alt="Content Mesh" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.gatsbyjs.org/blog/2018-10-04-journey-to-the-content-mesh/" rel="noopener noreferrer"&gt;https://www.gatsbyjs.org/blog/2018-10-04-journey-to-the-content-mesh/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You don't necessarily have to reach out to only one host for an API, but you can reach out to as many as you need (but try not to go overboard).&lt;/p&gt;

&lt;p&gt;For instance, if you have a headless &lt;a href="https://wordpress.org/" rel="noopener noreferrer"&gt;Wordpress&lt;/a&gt; API where you host your blog posts, a &lt;a href="https://cloudinary.com/" rel="noopener noreferrer"&gt;Cloudinary&lt;/a&gt; account where you store your specialized media, and an &lt;a href="https://www.elastic.co/" rel="noopener noreferrer"&gt;Elasticsearch&lt;/a&gt; instance that provides your search functionality, they all work together to provide a single experience to the people using your site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Markup
&lt;/h3&gt;

&lt;p&gt;This is the critical piece. Whether it's your hand written HTML or the code that compiles down to the HTML, it's the first part you're serving to the client. This is kind of a de facto piece of any website, but how you serve it is the most important piece.&lt;/p&gt;

&lt;p&gt;To be considered a JAMstack app, the HTML needs to be served statically, which basically means not being dynamically rendered from a server.&lt;/p&gt;

&lt;p&gt;If you're piecing a page together and serving it with PHP, it's probably not a JAMstack app. If you upload and serve a single HTML file from storage that constructs an app with Javascript, it sounds like a JAMstack app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo49zukuwxtyp6mvyzgo2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo49zukuwxtyp6mvyzgo2.png" alt="Static output from Gatsby on AWS S3" width="800" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But that doesn't mean we have to always build 100% of the app within the browser. Tools like Gatsby and other &lt;a href="https://www.staticgen.com/" rel="noopener noreferrer"&gt;static site generators&lt;/a&gt; allow us to pull in some or all of our API sources at build time and render the pages out as HTML files.&lt;/p&gt;

&lt;p&gt;Think if you have a Wordpress blog, we can pull in all of the posts and ultimately create a new HTML file for each post. That means we're going to be able to serve a precompiled version of the page directly to the browser which usually equates to a quicker &lt;a href="https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint" rel="noopener noreferrer"&gt;first paint&lt;/a&gt; and faster experience for your visitor.&lt;/p&gt;

&lt;h3&gt;
  
  
  One note about "hosting"
&lt;/h3&gt;

&lt;p&gt;Using the term hosting here can be misleading if you're new to the concept. Yeah, your site is technically getting hosted somewhere, but it's not in the traditional sense. You don't have a server that you're maintaining where you upload your files to with an &lt;a href="https://en.wikipedia.org/wiki/File_Transfer_Protocol" rel="noopener noreferrer"&gt;FTP&lt;/a&gt; client like &lt;a href="https://cyberduck.io/" rel="noopener noreferrer"&gt;Cyberduck&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Instead, whether your doing it yourself with S3 or piping it into Netlify (which is actually &lt;a href="https://www.netlify.com/blog/2018/05/14/how-netlify-migrated-to-a-fully-multi-cloud-infrastructure/" rel="noopener noreferrer"&gt;multi-cloud&lt;/a&gt;), your HTML and static assets are getting served from object storage. On the tail end of that you typically have a CDN like &lt;a href="https://www.cloudflare.com/" rel="noopener noreferrer"&gt;Cloudflare&lt;/a&gt; which caches those files at locations all over the world making your pages load faster for the people visiting your site.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzuv7w42ojm9lmvikxpfb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzuv7w42ojm9lmvikxpfb.jpg" alt="CDN distribution map" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So what makes a JAMstack app so great?
&lt;/h2&gt;

&lt;p&gt;JAMstack apps inherently satisfy most if not all of the &lt;a href="https://aws.amazon.com/blogs/apn/the-5-pillars-of-the-aws-well-architected-framework/" rel="noopener noreferrer"&gt;5 pillars of the AWS Well-Architected Framework&lt;/a&gt;. These are core concepts that AWS considers to deliver fast, secure, high-performing, resilient, and efficient infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj6zz347pvye0duyat9jh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj6zz347pvye0duyat9jh.jpg" alt="AWS Well-Architected" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's see how...&lt;/p&gt;

&lt;h3&gt;
  
  
  Speed
&lt;/h3&gt;

&lt;p&gt;The fact that you're serving JAMstack apps as static files directly from a CDN (usually) makes it likely your app is going to load super fast. Gone are the days where the server has to spend time building the page before responding; now you serve the page as just plain HTML "as is" or with some type of client side hydration like you'd see with &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost
&lt;/h3&gt;

&lt;p&gt;More often than not, JAMstack sites are going to run cheaper than their server side counterparts. Hosting static assets is cheap and now your page is being served at the same rate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scalability
&lt;/h3&gt;

&lt;p&gt;Since you're serving your files off of static hosting, likely a CDN, that pretty much automatically gives you infinite scalability. Most providers will make this claim, meaning you'll have no trouble letting any influx of people hitting your site in through the front door.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maintenance
&lt;/h3&gt;

&lt;p&gt;The foundation of your static site isn't a server, meaning you don't need to maintain it. Whether it's Netlify, S3, or any other provider, your static HTML, CSS, and JS are maintained for you headache-free.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;p&gt;Doubling down on the lack of server that you have to personally maintain, you don't really need to worry as much about locking down ways for people to intrude.&lt;/p&gt;

&lt;p&gt;Instead, you'll need to focus mostly on permissions to lock down private content and assure your users that their personal information isn't publicly available.&lt;/p&gt;

&lt;h3&gt;
  
  
  But this also depends on your APIs
&lt;/h3&gt;

&lt;p&gt;As much as these points strike true for the static aspects of your site, keep in mind you still might depend on some type of API for your client-side experience.&lt;/p&gt;

&lt;p&gt;Try to take advantage of these requests at compile time when you can, such as with a static site generator. Otherwise you'll need to weigh the amount of hits you're making to a dynamic endpoint and how it impacts all of the points above for your overall experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is my website considered to be on the JAMstack?
&lt;/h2&gt;

&lt;p&gt;We already talked about the 3 components (Javascript, APIs, Markup), but what we didn't talk about is the fact that you don't necessarily have to use all 3 of them in order to consider your site worthy of the JAM label.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6lqedkkvbgvgalo06f9p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6lqedkkvbgvgalo06f9p.gif" alt="Wayne's World " width="480" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Really it all boils down to the Markup and how you serve it. Instead of your Rails app rendering your HTML for you, you might host a precompiled React app on S3 that reaches out to Rails via a set of APIs.&lt;/p&gt;

&lt;p&gt;But you don't even need to have APIs. You don't even need to have Javascript! As long as you're serving an HTML file without it having to be compiled on a server at request time (aka pre-rendering it), you've got yourself a JAMstack site.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are some examples of JAMstack?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  freecodecamp.org
&lt;/h3&gt;

&lt;p&gt;Yes! freecodecamp.org and its learning portal &lt;a href="https://www.freecodecamp.org/news/freecodecamp-jamstack/" rel="noopener noreferrer"&gt;is a JAMstack site&lt;/a&gt; built on Gatsby. Even with the complexities of providing an app to take code courses with, freeCodeCamp is able to pull together the power of a static site generator and powerful APIs to bring people around the world the power of learning code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F41bvqw8j6enu7ylcju7w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F41bvqw8j6enu7ylcju7w.jpg" alt="https://www.freecodecamp.org/" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see Quincy from freeCodeCamp talk more about this at the 2018 JAMstack_conf:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=e5H7CI3yqPY" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=e5H7CI3yqPY&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: the News and Forum portals are not currently JAMstack sites.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Impossible Foods
&lt;/h3&gt;

&lt;p&gt;The main website for &lt;a href="https://impossiblefoods.com/" rel="noopener noreferrer"&gt;Impossible Foods&lt;/a&gt; is no other than a Gatsby site! Everything from their recipes to their location finder are all compiled through our favorite "blazing fast" static site generator.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdg01tob69zjqvu0em33t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdg01tob69zjqvu0em33t.jpg" alt="https://impossiblefoods.com/" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  web.dev
&lt;/h3&gt;

&lt;p&gt;Google's &lt;a href="https://web.dev/" rel="noopener noreferrer"&gt;web.dev&lt;/a&gt; resource center is built out using the growing &lt;a href="https://www.11ty.dev/" rel="noopener noreferrer"&gt;11ty&lt;/a&gt;. You can even find the code made open source at: &lt;a href="https://github.com/GoogleChrome/web.dev" rel="noopener noreferrer"&gt;https://github.com/GoogleChrome/web.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzzh8qwwozdsg27ex4e9u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzzh8qwwozdsg27ex4e9u.jpg" alt="https://web.dev/" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are some tools I can use to build JAMstack sites or apps?
&lt;/h2&gt;

&lt;p&gt;The good news with all of this buzz is there are a ton of tools currently available and a ton more on the way. They might still be a little rough around the edges, but that's because this is a brave new world of tooling and that takes some smoothing out to get just right.&lt;/p&gt;

&lt;h3&gt;
  
  
  Constructing your app
&lt;/h3&gt;

&lt;p&gt;This is the fun part. How are you going to build your app? With &lt;a href="https://github.com/scullyio/scully" rel="noopener noreferrer"&gt;Scully&lt;/a&gt; &lt;a href="https://www.netlify.com/blog/2019/12/16/introducing-scully-the-angular-static-site-generator/" rel="noopener noreferrer"&gt;in the picture&lt;/a&gt;, you can pretty much pick your favorite flavor of UI framework and get off the ground running. Here's a few popular ones to get started, but by no means is it exhaustive.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.11ty.dev/" rel="noopener noreferrer"&gt;11ty&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.gatsbyjs.org/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://gohugo.io/" rel="noopener noreferrer"&gt;Hugo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.nift.cc/" rel="noopener noreferrer"&gt;Nift&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/scullyio/scully" rel="noopener noreferrer"&gt;Scully&lt;/a&gt; (for you Angular fans)&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.staticgen.com/" rel="noopener noreferrer"&gt;And many more...&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Need me to pick one?&lt;/em&gt; Start with Gatsby and &lt;a href="https://github.com/colbyfayock/gatsby-starter-sass" rel="noopener noreferrer"&gt;bootstrap with a simple starter&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Serving your app
&lt;/h3&gt;

&lt;p&gt;I like to think of this as the easy part depending on your setup. Tools like Netlify and Zeit make this a breeze to configure by hooking into your Github repo and building anytime a new commit gets pushed, but of course you have options like AWS if you want more control.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://aws.amazon.com/getting-started/projects/host-static-website/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-static-website" rel="noopener noreferrer"&gt;Azure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://cloud.google.com/storage/docs/hosting-static-website" rel="noopener noreferrer"&gt;GCP&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;Github Pages&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://surge.sh/" rel="noopener noreferrer"&gt;Surge&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://zeit.co/" rel="noopener noreferrer"&gt;Zeit&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Need me to pick one?&lt;/em&gt; Start with Netlify and &lt;a href="https://www.netlify.com/blog/2016/09/29/a-step-by-step-guide-deploying-on-netlify/" rel="noopener noreferrer"&gt;take 5 minutes to deploy&lt;/a&gt; that Gatsby site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making your app dynamic
&lt;/h3&gt;

&lt;p&gt;Really this can be anything that can be used as an API making requests from the browser. I'm not going to list a bunch of examples per type, but here are a few tools and places you can find some resources.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://auth0.com/" rel="noopener noreferrer"&gt;Auth0&lt;/a&gt; - Authentication&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://cloudinary.com/" rel="noopener noreferrer"&gt;Cloudinary&lt;/a&gt; - Media management&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://analytics.google.com/analytics/web/#/" rel="noopener noreferrer"&gt;Google Analytics&lt;/a&gt; - Web traffic analytics&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://headlesscms.org/" rel="noopener noreferrer"&gt;headlesscms.org&lt;/a&gt; - Endless list of headless CMSs&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.sanity.io/" rel="noopener noreferrer"&gt;Sanity&lt;/a&gt; - CMS&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://serverless.com/" rel="noopener noreferrer"&gt;Serverless Framework&lt;/a&gt; - DIY, easy to deploy serverless resources&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://snipcart.com/" rel="noopener noreferrer"&gt;Snipcart&lt;/a&gt; - Ecommerce&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://stripe.com/" rel="noopener noreferrer"&gt;Stripe&lt;/a&gt; - Payment management&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/agarrharr/awesome-static-website-services" rel="noopener noreferrer"&gt;And a bunch of other resources...&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://headlesscms.org/" rel="noopener noreferrer"&gt;And a bunch of other CMS choices...&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://jamstack.wtf/" rel="noopener noreferrer"&gt;And some general info and tools...&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  And how about general resources to learn?
&lt;/h3&gt;

&lt;p&gt;You can find a lot of resources to get up and running quickly in the JAMstack world.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.freecodecamp.org/news/how-to-host-and-deploy-a-static-website-or-jamstack-app-to-s3-and-cloudfront/" rel="noopener noreferrer"&gt;How to host and deploy a static website or JAMstack app to AWS S3 and CloudFront&lt;/a&gt; from me on freeCodeCamp&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.netlify.com/blog/2016/02/24/a-step-by-step-guide-gatsby-on-netlify/" rel="noopener noreferrer"&gt;A Step-by-Step Guide: Gatsby on Netlify&lt;/a&gt; from Netlify&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.filamentgroup.com/lab/build-a-blog/" rel="noopener noreferrer"&gt;Build your own Blog from Scratch using Eleventy&lt;/a&gt; from filament group&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.freecodecamp.org/news/a-beginners-guide-on-how-to-host-a-static-site-with-aws/" rel="noopener noreferrer"&gt;How to Host your Static Website with AWS - A Beginner's Guide&lt;/a&gt; from freeCodeCamp&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://snipcart.com/blog/hugo-tutorial-static-site-ecommerce" rel="noopener noreferrer"&gt;Hugo Tutorial: How to Build &amp;amp; Host a (Very Fast) Static E-Commerce Site&lt;/a&gt; from SnipCart&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.freecodecamp.org/news/building-jamstack-apps/" rel="noopener noreferrer"&gt;How to Build Authenticated Serverless JAMstack Apps with Gatsby and Netlify&lt;/a&gt; from freeCodeCamp&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Expect to see more
&lt;/h2&gt;

&lt;p&gt;Similar to its serverless counterpart, the days of JAMstack are young. As time goes on, we'll be seeing the tooling mature and expand providing new exciting ways for us to quickly build fast sites that anyone can use.&lt;/p&gt;

&lt;p&gt;Join in the conversation on Twitter and &lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;let me know&lt;/a&gt; what your favorite part of building a JAMstack site is!&lt;/p&gt;

&lt;h2&gt;
  
  
  Missing something?
&lt;/h2&gt;

&lt;p&gt;Missing your favorite JAMstack tool or an awesome example? &lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;Ping me on Twitter&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Get more content straight your inbox!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐦 &lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📹 &lt;a href="https://youtube.com/colbyfayock" rel="noopener noreferrer"&gt;Subscribe to my Youtube Channel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🗞️ &lt;a href="https://www.colbyfayock.com/newsletter/" rel="noopener noreferrer"&gt;Sign up for my Newsletter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>jamstack</category>
      <category>static</category>
      <category>website</category>
    </item>
    <item>
      <title>What is linting and how can it save you time?</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Tue, 28 Apr 2020 13:16:18 +0000</pubDate>
      <link>https://dev.to/colbyfayock/what-is-linting-and-how-can-it-save-you-time-2dde</link>
      <guid>https://dev.to/colbyfayock/what-is-linting-and-how-can-it-save-you-time-2dde</guid>
      <description>&lt;p&gt;One of the biggest challenges in software development is time. It's something we can't easily get more of, but linting can help us make the most out of the time we have.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what is linting?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;lint&lt;/strong&gt;, or a &lt;strong&gt;linter&lt;/strong&gt;, is a tool that analyzes source code to flag programming errors, bugs, stylistic errors, and suspicious constructs.&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Lint(software)" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Lint(software)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simply put, a linter is a tool that programmatically scans your code with the goal of finding issues that can lead to bugs or inconsistencies with code health and style. Some can even help fix them for you!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkd0ur6nyelbzjdzpua4u.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkd0ur6nyelbzjdzpua4u.gif" alt="Michael Scott - Tell me more" width="498" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take for instance, the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const test = 'I am a test';
console.log(`Test: ${test}`);
const test = 'Another one.';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're declaring the constant &lt;code&gt;test&lt;/code&gt; twice, which our javascript engine won't be happy about. With the proper linter settings and watch configuration, instead of getting caught later as an error when the code runs, you'll immediately get an error through your linter running in the background:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  10:9  error  Parsing error: Identifier 'test' has already been declared

   8 |   const test = 'I am a test';
   9 |   console.log(`Test: ${2}`);
&amp;gt; 10 |   const test = 'Another one.';
     |         ^
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It might be pretty obvious that you have 2 of the same &lt;code&gt;const&lt;/code&gt; declarations given this is only 3 lines, but in a more complex application, this can save tons of time having to hunt down a pesky bug that's not always obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What all can linting help with?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://eslint.org/docs/rules/" rel="noopener noreferrer"&gt;Lots of things&lt;/a&gt;, including but not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Flagging bugs in your code from syntax errors&lt;/li&gt;
&lt;li&gt;  Giving you warnings when code may not be intuitive&lt;/li&gt;
&lt;li&gt;  Providing suggestions for common best practices&lt;/li&gt;
&lt;li&gt;  Keeping track of TODO's and FIXME's&lt;/li&gt;
&lt;li&gt;  Keeping a consistent code style&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most things you can think of probably already &lt;a href="https://github.com/dustinspecker/awesome-eslint" rel="noopener noreferrer"&gt;exist in one form or another&lt;/a&gt;, and if not, you can even &lt;a href="https://gist.github.com/sindresorhus/1656c46f23545deff8cc713649dcff26" rel="noopener noreferrer"&gt;create custom rules&lt;/a&gt; that fit your needs!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How is this actually helping or why should I care?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Probably the biggest overlying theme of the list above is the fact that these issues will be called out immediately. No longer will these issues creep up on you in the middle of running your app or give someone anxiety during a code review. No longer will you and your reviewer endlessly fight passive aggressively through the comments about whether or not to include a semicolon at the end of JS statements (&lt;a href="https://stackoverflow.com/a/444082" rel="noopener noreferrer"&gt;you should&lt;/a&gt; 🔥).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxairzo63e2423xnjca3a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxairzo63e2423xnjca3a.jpg" alt="Grandma looking for a semicolon" width="500" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of those moments that stop you from being productive because of a silly syntax error or the micro-interactions you and your teammates have during a review take time. They add up and end up taking away the time you can spend fixing another bug or developing the next great feature of your product.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;So how do I actually get started?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Even though there are linters for most, if not all, other mainstream languages, for the purpose of this post, I'm going to focus on Javascript. The same principles apply, but the tooling may be a bit different.&lt;/p&gt;

&lt;p&gt;I'm going to run through how you can get set up for basic linting in a React app. You can easily follow along by spinning up your own React app or using my &lt;a href="https://www.gatsbyjs.org/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt; starter: &lt;a href="https://github.com/colbyfayock/gatsby-starter-sass#starting-from-scratch" rel="noopener noreferrer"&gt;https://github.com/colbyfayock/gatsby-starter-sass#starting-from-scratch&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Your Linter&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To get started, we first need a linter. &lt;a href="https://trends.google.com/trends/explore?geo=US&amp;amp;q=eslint,jshint,jslint" rel="noopener noreferrer"&gt;Probably the most popular&lt;/a&gt; in the Javascript world is &lt;a href="https://eslint.org/" rel="noopener noreferrer"&gt;ESLint&lt;/a&gt;. Your linter will actually be the engine for defining rules and parsing your files to test against. ESLint is available as an &lt;a href="https://www.npmjs.com/package/eslint" rel="noopener noreferrer"&gt;npm package&lt;/a&gt; by itself and &lt;a href="https://eslint.org/docs/user-guide/getting-started" rel="noopener noreferrer"&gt;once installed&lt;/a&gt;, out of the box it allows you to set up a basic configuration file and hit the ground running with some command line tools.&lt;/p&gt;

&lt;p&gt;Let's first add our ESLint dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add eslint -D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're installing this as a &lt;code&gt;devDependency&lt;/code&gt; (hence the &lt;code&gt;-D&lt;/code&gt; flag), because this isn't something our application needs to run. After it's successfully installed, let's add it to our &lt;code&gt;package.json&lt;/code&gt; as a script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
"scripts": {
  ...
  "lint": "eslint .  --ext .js"
  ...
},
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above, we're running our linter on the entire project directory on any file that has an extension of &lt;code&gt;.js&lt;/code&gt;. If you're working with a large project with many file types, maybe even some you don't want linted, you can &lt;a href="https://eslint.org/docs/user-guide/command-line-interface" rel="noopener noreferrer"&gt;change that flag or be more specific&lt;/a&gt; with other options.&lt;/p&gt;

&lt;p&gt;To support ESLint, we'll need to do one more thing. Let's add a file at the root of our project (probably where your &lt;code&gt;package.json&lt;/code&gt; is) called &lt;code&gt;.eslintrc.js&lt;/code&gt; and make the contents of the file simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you're ready, you can run &lt;code&gt;yarn lint&lt;/code&gt; and... get an error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6lerf87cd8lwe7lyogrm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6lerf87cd8lwe7lyogrm.jpg" alt="Lint results - Import errors" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is okay, and expected in our project, so let's move on.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Your Parser&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A common tool in the chain for Javascript developers is &lt;a href="https://babeljs.io/" rel="noopener noreferrer"&gt;Babel&lt;/a&gt;, which allows you to write code with features that may not be supported in all browsers, such as using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions" rel="noopener noreferrer"&gt;arrow functions&lt;/a&gt;, that are available in &lt;a href="http://es6-features.org/#Constants" rel="noopener noreferrer"&gt;ES6&lt;/a&gt;, and other conventions like importing files via &lt;code&gt;import&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The code you write may already run through Babel to work in a browser, but that doesn't apply to ESLint by default, so ESLint allows you to specify a parser that allows the linting processing to look at the same code as your browser sees. In this case we'll want to use &lt;a href="https://github.com/babel/babel-eslint" rel="noopener noreferrer"&gt;Babel's ESLint&lt;/a&gt; parser that's made available to us.&lt;/p&gt;

&lt;p&gt;To set that up, we'll want to first install our dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add babel-eslint -D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typically if you're using &lt;code&gt;babel-eslint&lt;/code&gt; you'll want to make sure &lt;code&gt;babel&lt;/code&gt; is installed next to it, but in our case, Gatsby already uses &lt;code&gt;babel&lt;/code&gt;, so we don't necessarily need to add it. After that's set up, we'll want to update our &lt;code&gt;.eslintrc.js&lt;/code&gt; config file with some new options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
    "env": {
        "browser": true,
        "node": true,
        "es6": true
    },
    "parser": "babel-eslint"
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we're letting ESLint know that our environment will be run in node (Gatsby's precompiling), inside the browser (the app), and it will use ES6. This helps ESLint know how to run your code. Additionally, we want to set up our parser to be &lt;code&gt;babel-eslint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once we're ready to go, run &lt;code&gt;yarn lint&lt;/code&gt; again and... well nothing really happened.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2gc5h8bw03w6qux6i837.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2gc5h8bw03w6qux6i837.jpg" width="800" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lint results - Nothing happened&lt;/p&gt;

&lt;p&gt;This is still expected, as we don't have any rules set up!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Plugins for your code&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Writing a &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; app? The Babel parser may help you transform your code, but you might have a hard time being productive, as ESLint needs to understand how it should work to lint your React files.&lt;/p&gt;

&lt;p&gt;Part of the beauty of ESLint is that it allows you to &lt;a href="https://eslint.org/docs/developer-guide/working-with-plugins" rel="noopener noreferrer"&gt;configure plugins&lt;/a&gt; that have the opportunity to create and set rules for you. Luckily, along with our Babel parser above that does some of the heavy lifting, we have a &lt;a href="https://github.com/yannickcr/eslint-plugin-react" rel="noopener noreferrer"&gt;React plugin&lt;/a&gt; available that does just that and takes care of linting the JSX for us.&lt;/p&gt;

&lt;p&gt;Let's first install our dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add eslint-plugin-react -D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Further, let's update our &lt;code&gt;.eslintrc.js&lt;/code&gt; file again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
    "settings": {
        "react": {
            "version": "detect"
        }
    },
    "env": {
        "browser": true,
        "node": true,
        "es6": true
    },
    "plugins": [
        "react"
    ],
    "parser": "babel-eslint"
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we're adding here is a setting that automatically detects what React version you're using, which is helpful to let your linting get parsed properly, and then set up our react plugin that we installed above.&lt;/p&gt;

&lt;p&gt;For one last final time, we will run our &lt;code&gt;lint&lt;/code&gt; script and get nothing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2gc5h8bw03w6qux6i837.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2gc5h8bw03w6qux6i837.jpg" width="800" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lint results - Nothing happened&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rules defined by others's opinions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you're not really sure where to get started or just want to quickly get up and running, it's recommend that you enable &lt;a href="https://eslint.org/docs/rules/" rel="noopener noreferrer"&gt;ESLint's own recommended rules&lt;/a&gt;. Let's add this to our &lt;code&gt;.eslintrc.js&lt;/code&gt; config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
    "settings": {
        "react": {
            "version": "detect"
        }
    },
    "env": {
        "browser": true,
        "node": true,
        "es6": true
    },
    "plugins": [
        "react"
    ],
    "extends": [
        "eslint:recommended"
    ],
    "parser": "babel-eslint"
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And let's run our &lt;code&gt;yarn lint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Woah! This will immediately give you a lot errors, it seems like something's wrong.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2iw4hpuputxc6cvr2e9y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2iw4hpuputxc6cvr2e9y.jpg" alt="Lint results - React errors" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we're running a React app, we also want to make sure our linter understands the rules it should follow, so let's also add our React plugin to the &lt;code&gt;.eslintrc.js&lt;/code&gt; config setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "extends": [
        "eslint:recommended",
        "plugin:react/recommended"
    ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if you run &lt;code&gt;yarn lint&lt;/code&gt;, you get something a little more logical.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1ecgzpj5snxhfvthcivh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1ecgzpj5snxhfvthcivh.jpg" alt="Lint results - Normal errors" width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're following along, it looks like our starter app had a misplaced semicolon and a missing prop in our &lt;code&gt;propTypes&lt;/code&gt; validation for &lt;code&gt;Layout.js&lt;/code&gt;. Writing this helped me fix my own repo! 🎉&lt;/p&gt;

&lt;p&gt;Going further, if those don't seem to fit your needs, lots of developers and teams have published their own configurations that ESLint allows you to easily tap into.&lt;/p&gt;

&lt;p&gt;Some popular ones include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.npmjs.com/package/eslint-config-airbnb" rel="noopener noreferrer"&gt;Airbnb's config&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/standard/eslint-config-semistandard" rel="noopener noreferrer"&gt;Semistandard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/google/eslint-config-google" rel="noopener noreferrer"&gt;Google's JS Style Guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not happy with the options available? You can even &lt;a href="https://eslint.org/docs/6.0.0/developer-guide/shareable-configs" rel="noopener noreferrer"&gt;create and publish your own&lt;/a&gt; to either layer on top of others as a starting point or give it a go from scratch.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Let it do the work (most of it)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You don't think I'm going to make you fix all of those thing yourself do you? Well, you may have to fix some, but let's try to get ESLint to fix some of it for us.&lt;/p&gt;

&lt;p&gt;If you noticed after we ran the command above, ESLint gave us an extra message:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbkxkmpmhbb5obho1n290.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbkxkmpmhbb5obho1n290.jpg" alt="Lint results - Option to fix" width="800" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So let's give it a try! Let's run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn lint --fix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And what do you know, it now only gives us 1 linting error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbo7zk6pmho1zfi4bv33r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbo7zk6pmho1zfi4bv33r.jpg" alt="Lint results - 1 error" width="800" height="153"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Turns out ESLint was able to fix our semicolon issue automatically, but we'll still have to add &lt;code&gt;pageName&lt;/code&gt; to our &lt;code&gt;Layout&lt;/code&gt;'s &lt;code&gt;propTypes&lt;/code&gt; manually, not too much of a lift.&lt;/p&gt;

&lt;p&gt;Running one more time and finally nothing again! But this time because everything's looking good.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2gc5h8bw03w6qux6i837.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2gc5h8bw03w6qux6i837.jpg" width="800" height="78"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lint results - No errors&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Go forth and write messy code!&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq8tmgfxf34ubw8h6cylr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq8tmgfxf34ubw8h6cylr.gif" alt="Bruce Almighty - Typing" width="490" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kidding 😜 The good news here, is now you can easily take a look at the general health of your codebase as well as hopefully fix most of it automatically. This is going to save a lot of headaches as you work with others on your team, and generally, it's nice to have all of your code neat and tidy.&lt;/p&gt;

&lt;p&gt;This post is just getting started. ESLint is a wide open book with tons of plugins and rules, and it's not the only linting tool in the game. Play around and find what fits best for you and your team. The little time spent configuring it to your app will save you lots more time in the long run.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Other linting tools to check out&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://jshint.com/" rel="noopener noreferrer"&gt;JSHint&lt;/a&gt;: an alternative to ESLint&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/stylelint/stylelint" rel="noopener noreferrer"&gt;Stylelint&lt;/a&gt;: a linting tool for CSS and CSS-like syntaxes like &lt;a href="https://sass-lang.com/" rel="noopener noreferrer"&gt;Sass&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/dustinspecker/awesome-eslint" rel="noopener noreferrer"&gt;Awesome ESLint&lt;/a&gt;: a simple list of awesome configs, parsers, plugins, and other tools to boost your ESLint game&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://webhint.io/" rel="noopener noreferrer"&gt;Webhint&lt;/a&gt;: linting tool for accessibility, speed, and more website best practices&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/evcohen/eslint-plugin-jsx-a11y" rel="noopener noreferrer"&gt;A11y JSX Plugin&lt;/a&gt;: ESLint plugin for checking accessibility rules on JSX elements&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get more content straight your inbox!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐦 &lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📹 &lt;a href="https://youtube.com/colbyfayock" rel="noopener noreferrer"&gt;Subscribe to my Youtube Channel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🗞️ &lt;a href="https://www.colbyfayock.com/newsletter/" rel="noopener noreferrer"&gt;Sign up for my Newsletter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published on October 10, 2019 at &lt;a href="https://www.colbyfayock.com/2019/10/what-is-linting-and-how-can-it-save-you-time/" rel="noopener noreferrer"&gt;colbyfayock.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>codequality</category>
      <category>eslint</category>
      <category>tools</category>
    </item>
    <item>
      <title>use-custom-hook: Custom React Hook starter</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Mon, 13 Apr 2020 13:29:55 +0000</pubDate>
      <link>https://dev.to/colbyfayock/use-custom-hook-custom-react-hook-starter-n47</link>
      <guid>https://dev.to/colbyfayock/use-custom-hook-custom-react-hook-starter-n47</guid>
      <description>&lt;p&gt;Make spinning up and publishing a new custom React Hook easy!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/use-custom-hook" rel="noopener noreferrer"&gt;github.com/colbyfayock/use-custom-hook&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to get started
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git clone https://github.com/colbyfayock/use-custom-hook [directory]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd [directory]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;yarn install &amp;amp;&amp;amp; yarn setup&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd [hook-name] &amp;amp;&amp;amp; npm publish&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A ready-to-use hook source&lt;/li&gt;
&lt;li&gt;A next.js example / demo page&lt;/li&gt;
&lt;li&gt;Scripts ready to compile both&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Want more?
&lt;/h2&gt;

&lt;p&gt;Let me know what you think this is missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enjoy!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/use-custom-hook" rel="noopener noreferrer"&gt;github.com/colbyfayock/use-custom-hook&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Get more content straight your inbox!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐦 &lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📹 &lt;a href="https://youtube.com/colbyfayock" rel="noopener noreferrer"&gt;Subscribe to my Youtube Channel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🗞️ &lt;a href="https://www.colbyfayock.com/newsletter/" rel="noopener noreferrer"&gt;Sign up for my Newsletter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>hooks</category>
      <category>javascript</category>
      <category>git</category>
    </item>
    <item>
      <title>How to create a Coronavirus (COVID-19) Dashboard &amp; Map App with Gatsby and Leaflet</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Mon, 06 Apr 2020 12:15:06 +0000</pubDate>
      <link>https://dev.to/colbyfayock/how-to-create-a-coronavirus-covid-19-dashboard-map-app-with-gatsby-and-leaflet-3pa0</link>
      <guid>https://dev.to/colbyfayock/how-to-create-a-coronavirus-covid-19-dashboard-map-app-with-gatsby-and-leaflet-3pa0</guid>
      <description>&lt;p&gt;The Coronavirus (COVID-19) pandemic has swiftly changed how all of us interact day to day. How can we use available APIs to build a mapping app that shows the impact it has had on the world?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; The original NovelCOVID API v1 endpoint has been deprecated. Please update and use the following instead: &lt;a href="https://corona.lmao.ninja/v2/countries" rel="noopener noreferrer"&gt;https://corona.lmao.ninja/v2/countries&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Author's Note: This is meant to be a demo and proof of concept for putting together an impactful mapping application using real life data. For complete and accurate analysis, please make sure to use tools like &lt;a href="https://www.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6" rel="noopener noreferrer"&gt;Johns Hopkins University dashboard&lt;/a&gt;. Stay home and be safe! ❤️&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are we going to build?
&lt;/h2&gt;

&lt;p&gt;We'll be putting together a mapping application that uses an API containing recent Coronavirus statistics and maps out the locations and impact each country is facing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F37ftv6md4p48go5u5ns1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F37ftv6md4p48go5u5ns1.jpg" alt="Coronavirus map dashboard demo" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the map, we'll show a marker for each country with the number of confirmed cases. On top of that, we'll include a little popup tooltip that shows more in depth information.&lt;/p&gt;

&lt;p&gt;The map we'll build will mostly look like the above, but will look a little simpler. We'll utilize the OpenStreetMap public tileserver instead of using a custom &lt;a href="https://www.mapbox.com/" rel="noopener noreferrer"&gt;Mapbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get started, we're going to use this &lt;a href="https://github.com/colbyfayock/gatsby-starter-leaflet" rel="noopener noreferrer"&gt;Leaflet Gatsby Starter&lt;/a&gt; I created to make the initial setup a little smoother. With our app bootstrapped, we'll fetch our data and add markers to the map with our data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Woah, a mapping app?
&lt;/h2&gt;

&lt;p&gt;Yup. If you haven't played with maps before, don't be discouraged! It's not as bad as you probably think. If you'd rather start with mapping basics, you can &lt;a href="https://www.freecodecamp.org/news/easily-spin-up-a-mapping-app-in-react-with-leaflet/" rel="noopener noreferrer"&gt;read more about how mapping works&lt;/a&gt; first.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do we need before we get started?
&lt;/h2&gt;

&lt;p&gt;If you followed along with my previous tutorials for &lt;a href="https://www.freecodecamp.org/news/create-your-own-santa-tracker-with-gatsby-and-react-leaflet/" rel="noopener noreferrer"&gt;building a Santa Tracker&lt;/a&gt; or &lt;a href="https://www.freecodecamp.org/news/how-to-create-a-summer-road-trip-mapping-app-with-gatsby-and-leaflet/" rel="noopener noreferrer"&gt;creating a Summer Road Trip map&lt;/a&gt;, you can follow the same steps to get started. If not, we'll want to make sure we have the following set up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;node&lt;/a&gt; or &lt;a href="https://yarnpkg.com/en/" rel="noopener noreferrer"&gt;yarn&lt;/a&gt; - I'll be using yarn, but you can substitute with npm where appropriate&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.gatsbyjs.org/docs/gatsby-cli/" rel="noopener noreferrer"&gt;Gatsby's CLI&lt;/a&gt; - &lt;code&gt;yarn global add gatsby-cli&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're not sure about one of the above, you can try checking out the beginning &lt;a href="https://www.freecodecamp.org/news/create-your-own-santa-tracker-with-gatsby-and-react-leaflet/" rel="noopener noreferrer"&gt;my previous tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We'll also want to set up a foundation for our map. We can do this by utilizing the Leaflet Gatsby Starter I put together that provides us a basic setup with &lt;a href="https://leafletjs.com/" rel="noopener noreferrer"&gt;Leaflet&lt;/a&gt; and &lt;a href="https://react-leaflet.js.org/" rel="noopener noreferrer"&gt;React Leaflet&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gatsby new my-coronavirus-map https://github.com/colbyfayock/gatsby-starter-leaflet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmja9v1hhz11806bb36vs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmja9v1hhz11806bb36vs.jpg" alt="Creating a new Leaflet Gatsby app in the terminal" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that's finished running, you can navigate to the newly created project directory and start your local development server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd my-coronavirus-map
yarn develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7eq0oks23wddjfwarscr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7eq0oks23wddjfwarscr.jpg" alt="Starting your Gatsby app in the terminal" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If all goes as planned, your server should start and you should now be able to see your basic mapping app in your browser!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzpz969btgwbr3pngqqby.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzpz969btgwbr3pngqqby.jpg" alt="New Leaflet Gatsby app in the browser" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-coronavirus-map/commits/master" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Cleaning up some unneeded code
&lt;/h2&gt;

&lt;p&gt;The Gatsby Starter we're using to spin up this app comes with some demo code that we don't need here. We'll want to make all of the changes below in the file &lt;code&gt;src/pages/index.js&lt;/code&gt;, which is the homepage of our app.&lt;/p&gt;

&lt;p&gt;First, let's remove everything from the &lt;code&gt;mapEffect&lt;/code&gt; function. This function is used to run code that fires when the map renders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// In src/pages/index.js
async function mapEffect({ leafletElement } = {}) {
  // Get rid of everything in here
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll also change the variable name of our &lt;code&gt;leafletElement&lt;/code&gt; simply for being able to more easily understand the code as we write it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function mapEffect({ leafletElement: map } = {}) {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we don't want a marker this time, so let's remove the &lt;code&gt;&amp;lt;Marker&lt;/code&gt; component from our &lt;code&gt;&amp;lt;Map&lt;/code&gt; component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Map {...mapSettings} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have those pieces cleared out, we can remove all of the following imports and variables from the top of our file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  useRef&lt;/li&gt;
&lt;li&gt;  Marker&lt;/li&gt;
&lt;li&gt;  promiseToFlyTo&lt;/li&gt;
&lt;li&gt;  getCurrentLocation&lt;/li&gt;
&lt;li&gt;  gatsby_astronaut&lt;/li&gt;
&lt;li&gt;  timeToZoom&lt;/li&gt;
&lt;li&gt;  timeToOpenPopupAfterZoom&lt;/li&gt;
&lt;li&gt;  timeToUpdatePopupAfterZoom&lt;/li&gt;
&lt;li&gt;  ZOOM&lt;/li&gt;
&lt;li&gt;  popupContentHello&lt;/li&gt;
&lt;li&gt;  popupContentGatsby&lt;/li&gt;
&lt;li&gt;  markerRef&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After, our map should still work, but not do anything.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd796l7zxafdvazbean5i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd796l7zxafdvazbean5i.jpg" alt="New mapping app with nothing going on" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-coronavirus-map/commit/a3e9cff3949bb7ebb7cc89166c875e97b6dcb5a8" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Fetching the Coronavirus data
&lt;/h2&gt;

&lt;p&gt;For our app, we're going to use the &lt;a href="https://github.com/NovelCOVID/API" rel="noopener noreferrer"&gt;NovelCOVID API&lt;/a&gt;. Particularly, we're going to use the &lt;a href="https://corona.lmao.ninja/countries" rel="noopener noreferrer"&gt;countries endpoint&lt;/a&gt; to fetch the list of our countries and the stats associated with them.&lt;/p&gt;

&lt;p&gt;For making requests, I personally like to use &lt;a href="https://github.com/axios/axios" rel="noopener noreferrer"&gt;axios&lt;/a&gt; as it has a nice to use API. If you want to use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" rel="noopener noreferrer"&gt;fetch&lt;/a&gt; or your own favorite request library, substitute that in for this step.&lt;/p&gt;

&lt;p&gt;We'll start by installing axios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that installs, remember to restart your server.&lt;/p&gt;

&lt;p&gt;Import the axios package ta the top of our &lt;code&gt;pages/index.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from 'axios';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we'll actually make our request. Inside our &lt;code&gt;mapEffect&lt;/code&gt; function, let's try to make a request to the API endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function mapEffect({ leafletElement: map } = {}) {
    let response;

    try {
      response = await axios.get('https://corona.lmao.ninja/countries');
    } catch(e) {
      console.log(`Failed to fetch countries: ${e.message}`, e);
      return;
    }

    const { data = [] } = response;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, we're doing the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Setting up a &lt;code&gt;response&lt;/code&gt; variable that will allow us to store the response&lt;/li&gt;
&lt;li&gt;  Adding a &lt;code&gt;try/catch&lt;/code&gt; block that will catch any API errors if the request fails&lt;/li&gt;
&lt;li&gt;  If the request is successful, we store the response in the &lt;code&gt;response&lt;/code&gt; variable&lt;/li&gt;
&lt;li&gt;  If the request fails, we console log out the error and return out of the function so we don't continue to run the code with a failed request&lt;/li&gt;
&lt;li&gt;  Once we have our response, we can destructure &lt;code&gt;data&lt;/code&gt; from the response and set the default value to an empty array, as that will be the type of data we need&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After that's set up, we can console log out the &lt;code&gt;data&lt;/code&gt; object and we'll see our data successfully fetched!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnymuvrcxejl0n3lk1y8j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnymuvrcxejl0n3lk1y8j.jpg" alt="Logging the Coronavirus location data to the browser console" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-coronavirus-map/commit/86bebfee4a34b9bad516879b228921cdaad55126" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; The previous commit includes a link to the original NovelCOVID v1 API endpoint which has now been deprecated. Please use this instead: &lt;a href="https://corona.lmao.ninja/v2/countries" rel="noopener noreferrer"&gt;https://corona.lmao.ninja/v2/countries&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-coronavirus-map/commit/e8f63c7ca60ec358b2edc9bc3ed8935be85b5573" rel="noopener noreferrer"&gt;See updated commit.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Transform the Coronavirus data into a geographic data format
&lt;/h2&gt;

&lt;p&gt;Now that we have our data, we can transform it into a geographic data format, particularly &lt;a href="https://geojson.org/" rel="noopener noreferrer"&gt;GeoJSON&lt;/a&gt;, that will allow us to interface with Leaflet.&lt;/p&gt;

&lt;p&gt;Let's start by adding this block of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { data = [] } = response;
const hasData = Array.isArray(data) &amp;amp;&amp;amp; data.length &amp;gt; 0;

if ( !hasData ) return;

const geoJson = {
  type: 'FeatureCollection',
  features: data.map((country = {}) =&amp;gt; {
    const { countryInfo = {} } = country;
    const { lat, long: lng } = countryInfo;
    return {
      type: 'Feature',
      properties: {
        ...country,
      },
      geometry: {
        type: 'Point',
        coordinates: [ lng, lat ]
      }
    }
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what are we doing here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We create a new constant called &lt;code&gt;hasData&lt;/code&gt; that checks if our &lt;code&gt;data&lt;/code&gt; variable is an array and has data&lt;/li&gt;
&lt;li&gt;  If we don't have data, we want to return out of the function, as we don't want to try to add data we don't have&lt;/li&gt;
&lt;li&gt;  We create a &lt;code&gt;geoJson&lt;/code&gt; object that will be our GeoJSON document&lt;/li&gt;
&lt;li&gt;  Our document is of type &lt;code&gt;FeatureCollection&lt;/code&gt; and as our &lt;code&gt;features&lt;/code&gt; we loop through our dataset&lt;/li&gt;
&lt;li&gt;  For each country in our data, we obtain the &lt;code&gt;lat&lt;/code&gt; and &lt;code&gt;lng&lt;/code&gt; to create a point for our map&lt;/li&gt;
&lt;li&gt;  We additionally add our country data as properties so we can access it within our mapping APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you &lt;code&gt;console.log&lt;/code&gt; this object our into your browser and copy the contents, you can paste this into geojson.io and see the location data show up correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbcd615ha02zb8t3mm4ac.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbcd615ha02zb8t3mm4ac.jpg" alt="Previewing Coronavirus location data on geojson.io" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this GeoJSON document, we'll now be able to add it to our map.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-coronavirus-map/commit/f0da2d05cbc16783322684da7a3efaa61022f5b6" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Adding the Coronavirus data to the map
&lt;/h2&gt;

&lt;p&gt;We have our GeoJSON document with our location data, so let's add it to the map.&lt;/p&gt;

&lt;p&gt;Let's start with this code block. It's a long one, but we'll break it down piece by piece:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const geoJsonLayers = new L.GeoJSON(geoJson, {
  pointToLayer: (feature = {}, latlng) =&amp;gt; {
    const { properties = {} } = feature;
    let updatedFormatted;
    let casesString;

    const {
      country,
      updated,
      cases,
      deaths,
      recovered
    } = properties

    casesString = `${cases}`;

    if ( cases &amp;gt; 1000 ) {
      casesString = `${casesString.slice(0, -3)}k+`
    }

    if ( updated ) {
      updatedFormatted = new Date(updated).toLocaleString();
    }

    const html = `
      &amp;lt;span class="icon-marker"&amp;gt;
        &amp;lt;span class="icon-marker-tooltip"&amp;gt;
          &amp;lt;h2&amp;gt;${country}&amp;lt;/h2&amp;gt;
          &amp;lt;ul&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Confirmed:&amp;lt;/strong&amp;gt; ${cases}&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Deaths:&amp;lt;/strong&amp;gt; ${deaths}&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Recovered:&amp;lt;/strong&amp;gt; ${recovered}&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Last Update:&amp;lt;/strong&amp;gt; ${updatedFormatted}&amp;lt;/li&amp;gt;
          &amp;lt;/ul&amp;gt;
        &amp;lt;/span&amp;gt;
        ${ casesString }
      &amp;lt;/span&amp;gt;
    `;

    return L.marker( latlng, {
      icon: L.divIcon({
        className: 'icon',
        html
      }),
      riseOnHover: true
    });
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what are we doing here?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We create a new instance of &lt;code&gt;L.GeoJSON&lt;/code&gt; which will transform our GeoJSON document into something Leaflet will understand&lt;/li&gt;
&lt;li&gt;  Inside that instance, we define a custom &lt;code&gt;pointToLayer&lt;/code&gt; function. This allows us to customize the map layer Leaflet creates for our map&lt;/li&gt;
&lt;li&gt;  In our function, we assign and create our datapoints that we want. Most of it is destructuring, but we format the cases count to show &lt;code&gt;1k+&lt;/code&gt; instead of &lt;code&gt;1000&lt;/code&gt; and a formatted date instead of the timestamp&lt;/li&gt;
&lt;li&gt;  We create an HTML string block which is used to define our map marker that will be added to the map. This also includes the HTML for the tooltip that will pop up when hovering over a marker&lt;/li&gt;
&lt;li&gt;  We return &lt;code&gt;L.marker&lt;/code&gt; with our custom configuration that includes a class of &lt;code&gt;icon&lt;/code&gt; for the container and our custom HTML.&lt;/li&gt;
&lt;li&gt;  Additionally, we add the &lt;code&gt;riseOnHover&lt;/code&gt; property so when hoving over a marker, it surfaces itself above over the other markers on the map&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also want to add a bit of CSS here so that we can make sure our markers show up in the map and are usable. Let's add this snippet to our &lt;code&gt;assets/stylesheets/components/_map.scss&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.icon-marker {

  display: flex;
  position: relative;
  justify-content: center;
  align-items: center;
  color: white;
  width: 3.6em;
  height: 3.6em;
  font-size: .7em;
  font-weight: bold;
  background-color: $red-800;
  border-radius: 100%;
  box-shadow: 0 2px 5px rgba(black, .9);

  &amp;amp;:hover {

    .icon-marker-tooltip {
      display: block;
    }

  }

}

.icon-marker-tooltip {

  display: none;
  position: absolute;
  bottom: 100%;
  width: 16em;
  font-size: 1.4em;
  padding: 1em;
  background-color: $blue-grey-900;
  border-radius: .4em;
  margin-bottom: 1em;
  box-shadow: 0 3px 5px rgba(black, .9);

  &amp;amp;:before {
    display: block;
    position: absolute;
    bottom: -.6em;
    left: 50%;
    content: '';
    width: 1.4em;
    height: 1.4em;
    background-color: $blue-grey-900;
    transform: rotate(45deg);
    margin-left: -.7em;
  }

  h2 {
    font-size: 1.5em;
    line-height: 1.2;
    margin-bottom: .1em;
    margin-top: 0;
  }

  h3 {
    font-size: 1.2em;
    margin: .1em 0;
    font-weight: normal;
    color: $blue-grey-100;
  }

  ul,
  p {
    font-weight: normal;
  }

  ul {
    list-style: none;
    padding: 0;
    margin: .6em 0 0;
  }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we're doing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We create our round markers using the &lt;code&gt;.icon-marker&lt;/code&gt; class and set up our &lt;code&gt;.icon-marker-tooltip&lt;/code&gt; class to show up when hovered over&lt;/li&gt;
&lt;li&gt;  Our &lt;code&gt;.icon-marker-tooltip&lt;/code&gt; class is hidden by default, as it's our tooltip, but we position it absolutely to appear over top of our marker and formatted the way we want it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And finally, once we have our &lt;code&gt;geoJsonLayers&lt;/code&gt; created with our styling added, we can add it to the map!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;geoJsonLayers.addTo(map)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5co1i4wknp6zp2auza9v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5co1i4wknp6zp2auza9v.jpg" alt="Map with Coronavirus location data" width="800" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you might be wondering why it doesn't appear to be centering properly. Go ahead and change the &lt;code&gt;LOCATION&lt;/code&gt; variable at the top of the &lt;code&gt;index.js&lt;/code&gt; file to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const LOCATION = {
  lat: 0,
  lng: 0
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that's set, when the page reloads, the map should be centered in the middle of the world!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq2h1h7em4sxlqhlfd9x0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq2h1h7em4sxlqhlfd9x0.jpg" alt="Map with Coronavirus location data centered with a tooltip" width="800" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/my-coronavirus-map/commit/49c78e4ef3e98c974fab7bca10b6f8f7578b42c2" rel="noopener noreferrer"&gt;Follow along with the commit!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Yay, we did it! 🎉
&lt;/h2&gt;

&lt;p&gt;If you followed along, you now have created your own Coronavirus map dashboard that gives some quick stats about the cases around the world.&lt;/p&gt;

&lt;p&gt;Take what you learned and run with it. You can apply this to any other type of data that you can imagine.&lt;/p&gt;

&lt;h2&gt;
  
  
  What else can we do?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Add more styles and a custom basemap
&lt;/h3&gt;

&lt;p&gt;In my original demo, I set up a custom basemap using &lt;a href="https://mapbox.com/" rel="noopener noreferrer"&gt;Mapbox&lt;/a&gt; that allows me to have a dark background making the markers easier to see.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwwxq3nixv9bnqwgxaubw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwwxq3nixv9bnqwgxaubw.jpg" alt="Creating a new basemap in Mapbox Studio" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mapbox is great and has a nice free tier if you're interested in getting started.&lt;/p&gt;

&lt;p&gt;Once you have a Mapbox account, you can even &lt;a href="https://api.mapbox.com/styles/v1/colbyfayock/ck8c2foj72lqk1jnug0g2haw0.html?fresh=true&amp;amp;title=copy&amp;amp;access_token=pk.eyJ1IjoiY29sYnlmYXlvY2siLCJhIjoiY2swODZzbXYxMGZzdzNjcXczczF6MnlvcCJ9.HCfgUYZUTP7uixjYF7tBSw" rel="noopener noreferrer"&gt;copy the style&lt;/a&gt; I used and make it your own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://api.mapbox.com/styles/v1/colbyfayock/ck8c2foj72lqk1jnug0g2haw0.html?fresh=true&amp;amp;title=copy&amp;amp;access_token=pk.eyJ1IjoiY29sYnlmYXlvY2siLCJhIjoiY2swODZzbXYxMGZzdzNjcXczczF6MnlvcCJ9.HCfgUYZUTP7uixjYF7tBSw" rel="noopener noreferrer"&gt;Basic Dark Mapbox Theme&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To learn how to integrate it, you can try to check out the source code of &lt;a href="https://github.com/colbyfayock/coronavirus-map-dashboard" rel="noopener noreferrer"&gt;my original demo&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/colbyfayock/coronavirus-map-dashboard" rel="noopener noreferrer"&gt;https://github.com/colbyfayock/coronavirus-map-dashboard&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add overview dashboard stats
&lt;/h3&gt;

&lt;p&gt;Dashboards with maps like the &lt;a href="https://www.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6" rel="noopener noreferrer"&gt;Johns Hopkins University app&lt;/a&gt; allows us to see more than a look on the map, but a glimpse at quick stats about the cases around the world.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzq9afw1lslv1kx91xner.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzq9afw1lslv1kx91xner.jpg" alt="Johns Hopkins University Coronavirus Map Dashboard - March 29, 2020" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/NovelCOVID/API" rel="noopener noreferrer"&gt;NovelCOVID API&lt;/a&gt; has more endpoints like &lt;code&gt;/all&lt;/code&gt; that provide a few global stats.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be safe and stay informed
&lt;/h2&gt;

&lt;p&gt;I want to reiterate that you should make sure you're staying up to date using official sources for information, such as the Johns Hopkins University dashboard. Though the data should be reliable, it should also be considered a proof of concept for building a map and referencing, but shouldn't be considered for any kind of statistical analysis.&lt;/p&gt;

&lt;p&gt;Please take care of yourself during these times. We're all in this together! ❤️&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to learn more about maps?
&lt;/h2&gt;

&lt;p&gt;You can check out a few of my other resources to get started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.freecodecamp.org/news/anyone-can-map-inspiration-and-an-introduction-to-the-world-of-mapping/" rel="noopener noreferrer"&gt;Anyone Can Map! Inspiration and an introduction to the world of mapping&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.freecodecamp.org/news/how-to-create-a-summer-road-trip-mapping-app-with-gatsby-and-leaflet/" rel="noopener noreferrer"&gt;How to Create a Summer Road Trip Mapping App with Gatsby and Leaflet&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.freecodecamp.org/news/create-your-own-santa-tracker-with-gatsby-and-react-leaflet/" rel="noopener noreferrer"&gt;How to Create your own Santa Tracker with Gatsby and React Leaflet&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.freecodecamp.org/news/easily-spin-up-a-mapping-app-in-react-with-leaflet/" rel="noopener noreferrer"&gt;How to build a mapping app in React the easy way with Leaflet&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get more content straight your inbox!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐦 &lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📹 &lt;a href="https://youtube.com/colbyfayock" rel="noopener noreferrer"&gt;Subscribe to my Youtube Channel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🗞️ &lt;a href="https://www.colbyfayock.com/newsletter/" rel="noopener noreferrer"&gt;Sign up for my Newsletter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published on March 29, 2020 at &lt;a href="https://www.colbyfayock.com/2020/03/how-to-create-a-coronavirus-covid-19-dashboard-map-app-with-gatsby-and-leaflet/" rel="noopener noreferrer"&gt;colbyfayock.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>leaflet</category>
      <category>mapping</category>
      <category>react</category>
    </item>
    <item>
      <title>Put Down the Javascript: Learn HTML &amp; CSS first</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Mon, 30 Mar 2020 12:14:05 +0000</pubDate>
      <link>https://dev.to/colbyfayock/put-down-the-javascript-learn-html-css-first-1cdl</link>
      <guid>https://dev.to/colbyfayock/put-down-the-javascript-learn-html-css-first-1cdl</guid>
      <description>&lt;p&gt;A growing trend in front end development is the idea that you can dive right into Javascript and succeed. Honestly, for better or worse you probably can. But you're just building on top of a fragile foundation that will come back to bite you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do I need HTML or CSS?
&lt;/h3&gt;

&lt;p&gt;The UI frameworks that we know today like &lt;a href="https://reactjs.org/" rel="noopener noreferrer"&gt;React&lt;/a&gt; and &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue&lt;/a&gt; build on top of the basic building blocks of a webpage: HTML and CSS. Though these UI frameworks supercharge these basics through some cool tools and Javascript, what you're building is fundamentally the same thing as the &lt;a href="https://www.spacejam.com/archive/spacejam/movie/jam.htm" rel="noopener noreferrer"&gt;Space Jam website&lt;/a&gt; from 1996.&lt;/p&gt;

&lt;p&gt;But I get it, writing HTML and CSS manually is dated right?&lt;/p&gt;

&lt;h3&gt;
  
  
  Understand what your tools are doing
&lt;/h3&gt;

&lt;p&gt;Having at least a basic understanding of what's going on under the hood will help you immensely as you develop and debug your applications.&lt;/p&gt;

&lt;p&gt;You might have run into a few odd things in the browser, such as why does HTML transform code there? Using the following as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;style&amp;gt;
p {
  color: purple;
}
&amp;lt;/style&amp;gt;
&amp;lt;h1&amp;gt;My Cool Page&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;
  Some cool stuff
  &amp;lt;div&amp;gt;Is this still cool?&amp;lt;/div&amp;gt;
&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you load this up in Chrome, you'll notice some changes...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4wt85etbh0xorn8mwd4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4wt85etbh0xorn8mwd4f.png" alt="Example browser fixed HTML" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why isn't all of my paragraph cool and purple?&lt;/p&gt;

&lt;p&gt;Well, turns out your browser is helpful and automatically fixes your code. A paragraph tag (&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;) &lt;a href="https://www.w3.org/TR/html401/struct/text.html#h-9.3.1" rel="noopener noreferrer"&gt;can not contain another block level element&lt;/a&gt;, so Chrome and other browsers will adjust your HTML on the fly to make it valid. HTML is very lenient this way! But this is a common bug that stumps developers old and new who just aren't familiar with how HTML works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffk2r2rl4totcei4rdomz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffk2r2rl4totcei4rdomz.png" alt="Gets Invalid HTML, Fixes It For You" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Learn the magic of CSS
&lt;/h3&gt;

&lt;p&gt;CSS can do a whole heck of a lot these days. It's so much more than setting a few colors, but gives you the ability to provide consistent UI patterns throughout your application.&lt;/p&gt;

&lt;p&gt;Don't be afraid of it! If you started in Javascript, you might be tempted to do everything there, but you'll quickly find managing all of the real power of CSS within your JS is a pain, and frankly, &lt;a href="https://www.colbyfayock.com/2019/07/you-dont-need-css-in-js-why-i-use-stylesheets" rel="noopener noreferrer"&gt;unnecessary unless you're Facebook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What can you do? Build &lt;a href="https://www.colbyfayock.com/2019/07/you-dont-need-css-in-js-why-i-use-stylesheets" rel="noopener noreferrer"&gt;the Alien movie title scene&lt;/a&gt; with pure CSS. Grab some &lt;a href="https://ianlunn.github.io/Hover/" rel="noopener noreferrer"&gt;hover effects for your buttons&lt;/a&gt;. Or just &lt;a href="https://daneden.github.io/animate.css/" rel="noopener noreferrer"&gt;animate anything&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;A favorite of mine is creating a fancy Facebook-like loading animation class that will apply an animated gradient background to anything you add it to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.loading {
  background: linear-gradient(90deg, #eff1f1 30%, #f7f8f8 50%, #eff1f1 70%);
  background-size: 400%;
  animation: loading 1.2s ease-in-out infinite;
}

@keyframes loading {
  0% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0 50%;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fduqaa8qzgv6m35jr6ti7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fduqaa8qzgv6m35jr6ti7.gif" alt="Example loading animation" width="800" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Crack open &lt;a href="https://codepen.io/colbyfayock/pen/aKKoJP" rel="noopener noreferrer"&gt;a codepen&lt;/a&gt; and try it yourself!&lt;/p&gt;

&lt;h3&gt;
  
  
  Make your search results relevant
&lt;/h3&gt;

&lt;p&gt;Search engines do their best to figure out how the content you write is relevant to users searching for it. But how you write your HTML makes a difference with helping them determine that value. A common mistake I see is using &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements" rel="noopener noreferrer"&gt;Heading&lt;/a&gt; elements incorrectly or simply not using them at all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h1&amp;gt;All&amp;lt;/h1&amp;gt;
&amp;lt;h1&amp;gt;My&amp;lt;/h1&amp;gt;
&amp;lt;h1&amp;gt;Content&amp;lt;/h1&amp;gt;
&amp;lt;h1&amp;gt;Is&amp;lt;/h1&amp;gt;
&amp;lt;h1&amp;gt;Important&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consider the outline of this blog post:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Put Down the Javascript - Learn HTML &amp;amp; CSS
  - Why do I need HTML or CSS?
  - Understand what Your tools are doing
  - Learn the magic of CSS
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Learn the magic of CSS" is not the key takeaway from the page, so I wouldn't want to feature that as the most important. The title of the post however, "Put Down the Javascript --- Learn HTML &amp;amp; CSS", reflects the overall story, making it the most important, so I would want to make it #1.&lt;/p&gt;

&lt;p&gt;So with my HTML, I would want to make it look something more like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h1&amp;gt;Put Down the Javascript - Learn HTML &amp;amp; CSS&amp;lt;/h1&amp;gt;
&amp;lt;h2&amp;gt;Why do I need HTML or CSS?&amp;lt;/h2&amp;gt;
&amp;lt;h2&amp;gt;Understand what Your tools are doing&amp;lt;/h2&amp;gt;
&amp;lt;h2&amp;gt;Put Down the JS - Learn HTML &amp;amp; CSS/h2&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets Google, Bing, and all the other search engines know exactly what should be the most important part of the page and help identify the general hierarchy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Drive accessibility by inclusive development
&lt;/h3&gt;

&lt;p&gt;By not coding responsibly, we automatically exclude people from accessing the site we work so hard to build. Often these people care about what's getting built just as much if not more than you and I do.&lt;/p&gt;

&lt;p&gt;By doing a little homework the first time and spending an extra second thinking about what we're writing, we can be inclusive to all friends visiting our sites.&lt;/p&gt;

&lt;p&gt;Take a simple navigation list commonly seen in most websites today. You might be tempted to write out a few &lt;code&gt;div&lt;/code&gt; s because they work right?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div className="nav"&amp;gt;
  &amp;lt;div&amp;gt;&amp;lt;a href="#"&amp;gt;Link 1&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div&amp;gt;&amp;lt;a href="#"&amp;gt;Link 2&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div&amp;gt;&amp;lt;a href="#"&amp;gt;Link 3&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue is, they're not as easy for screen readers to pick up on. To fix this, you /technically/ can write even less HTML ( &lt;code&gt;div&lt;/code&gt; is 3 characters, &lt;code&gt;ul&lt;/code&gt; and &lt;code&gt;li&lt;/code&gt; are 2 🙄).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ul className="nav"&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;Link 1&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;Link 2&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;Link 3&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Taking it a step further, if this is your navigation menu, wrap it in an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav" rel="noopener noreferrer"&gt;HTML 5 navigation element&lt;/a&gt; (&lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;) and &lt;a href="https://www.w3.org/WAI/tutorials/menus/structure/#identify-menus" rel="noopener noreferrer"&gt;users will now be able to directly access the menu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://a11yproject.com/" rel="noopener noreferrer"&gt;The A11y Project&lt;/a&gt; for more good tips on accessibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplify your code, embrace native functionality
&lt;/h3&gt;

&lt;p&gt;You would be surprised how much functionality &lt;a href="https://dev.to/ananyaneogi/html-can-do-that-c0n"&gt;exists natively in modern browsers&lt;/a&gt;, with more browser support than you probably need (sorry to those of you who still support IE9).&lt;/p&gt;

&lt;p&gt;With some basic HTML, you can build a text input that has searchable, autocomplete-like text in a dropdown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;label&amp;gt;My Favorite Color&amp;lt;/label&amp;gt;
&amp;lt;input type="text" name="color" list="colors"&amp;gt;
&amp;lt;datalist id="colors"&amp;gt;
  &amp;lt;option value="Magenta"&amp;gt;
  &amp;lt;option value="Purple"&amp;gt;
  &amp;lt;option value="Ultraviolet"&amp;gt;
&amp;lt;/datalist&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feuny9dul0p6gn0lcd7yg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feuny9dul0p6gn0lcd7yg.gif" alt="Favorite color selector" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Taking advantage of CSS pseudo selectors, we can dynamically style a checkbox-type element depending on if it's checked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;style&amp;gt;
.is-checked {
    display: none;
}

#my-checkbox:checked + span .is-checked {
    display: inline;
}

#my-checkbox:checked + span .not-checked {
    display: none;
}
&amp;lt;/style&amp;gt;

&amp;lt;label for="my-checkbox"&amp;gt;
  &amp;lt;input id="my-checkbox" type="checkbox" /&amp;gt;
  &amp;lt;span&amp;gt;
    &amp;lt;span class="not-checked"&amp;gt;Not Checked&amp;lt;/span&amp;gt;
    &amp;lt;span class="is-checked"&amp;gt;Checked&amp;lt;/span&amp;gt;
    &amp;lt;/span&amp;gt;
&amp;lt;/label&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fapz2w7jyrjno0kfyksq6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fapz2w7jyrjno0kfyksq6.gif" alt="Dynamic checkbox" width="518" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  This is Your Craft, Pay Attention to It
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuy0eigka0zsoz7n5k49k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuy0eigka0zsoz7n5k49k.png" alt="https://twitter.com/markdalgleish/status/1155430223963234304" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd wager the majority of the people reading this are doing so because they care about their code and are super passionate about what they do. Just like any other craft that came before development, practicing and focusing on the fundamentals will strengthen your ability as a developer. Bonus, you'll be getting an easy win by helping be more inclusive with your work and getting more people to your application!&lt;/p&gt;

&lt;h2&gt;
  
  
  Get more content straight your inbox!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐦 &lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📹 &lt;a href="https://youtube.com/colbyfayock" rel="noopener noreferrer"&gt;Subscribe to my Youtube Channel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🗞️ &lt;a href="https://www.colbyfayock.com/newsletter/" rel="noopener noreferrer"&gt;Sign up for my Newsletter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published on August 28, 2019 at &lt;a href="https://www.colbyfayock.com/2019/08/put-down-the-javascript-learn-html-css/" rel="noopener noreferrer"&gt;colbyfayock.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>html</category>
      <category>css</category>
      <category>fundamentals</category>
    </item>
    <item>
      <title>How to build a mapping app in React the easy way with Leaflet</title>
      <dc:creator>Colby Fayock</dc:creator>
      <pubDate>Fri, 27 Mar 2020 12:03:49 +0000</pubDate>
      <link>https://dev.to/colbyfayock/how-to-build-a-mapping-app-in-react-the-easy-way-with-leaflet-2o7c</link>
      <guid>https://dev.to/colbyfayock/how-to-build-a-mapping-app-in-react-the-easy-way-with-leaflet-2o7c</guid>
      <description>&lt;p&gt;Mapping is hard, but spinning up a new app that renders maps doesn't have to be. Here's how you can easily get started working with maps in a new React app.&lt;/p&gt;

&lt;h1&gt;
  
  
  Not that AAA map under your car seat
&lt;/h1&gt;

&lt;p&gt;Maps have been around for thousands of years, but they've become more complex and powerful within the last couple decades simply due to the fact that computers exist. This has enabled the creation of products we use every day - like Google Maps that help us get home from work and avoid traffic, or weather maps that allow us to check real time radar images. Taking that a step further, scientists use maps every day using data from satellite imagery to try to get a better understanding of our humble planet.&lt;/p&gt;

&lt;p&gt;This sounds hard...&lt;/p&gt;

&lt;h1&gt;
  
  
  Building maps
&lt;/h1&gt;

&lt;p&gt;Plot twist, it's not hard!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuoul2y2t634xot00o5pk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuoul2y2t634xot00o5pk.gif" alt="Final Space - What a twist!" width="500" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At least it's not hard to get started. Thankfully, the parts that are the hardest are already built into libraries that can easily be tapped into with JavaScript.&lt;/p&gt;

&lt;p&gt;Enter Leaflet...&lt;/p&gt;

&lt;h1&gt;
  
  
  Mapping Libraries
&lt;/h1&gt;

&lt;p&gt;There are a few libraries in the mapping space right now (like&lt;a href="https://openlayers.org/" rel="noopener noreferrer"&gt; OpenLayers&lt;/a&gt;), but we like &lt;a href="https://leafletjs.com/" rel="noopener noreferrer"&gt;Leaflet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To get started with Leaflet, first include the library's assets on your page. Next, mount the application onto a root element within the DOM with some basic settings. You can kind of think of it like how React mounts to a DOM node, but Leaflet itself doesn't use React. Once initialized, Leaflet allows you to start utilizing it's API to project a basemap, add layers, tiles on those layers, and even start to draw on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basemap? Layers? Tiles?
&lt;/h3&gt;

&lt;p&gt;To get the basic gist, think of a cake. Traditionally, cakes have different layers, some on the bottom, some on the top, some might just cover one side with icing. Your map layers function similarly. The bottom layer, which is your foundation, will be your "basemap". Below, we're seeing a snapshot of the 2018 California Camp Fire wildfires on top of NASA's &lt;a href="https://terra.nasa.gov/about/terra-instruments/modis" rel="noopener noreferrer"&gt;MODIS Aqua&lt;/a&gt; satellite imagery.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcnu3qecdemc3rbzhmc8h.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcnu3qecdemc3rbzhmc8h.jpg" alt="MODIS Aqua - California " width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, to get a basemap, we need the imagery to produce it, which is where tiles come in. A tile is a single image block that makes up your group of tiles that represent your layer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa11sp2kjplr0rcpp9hrk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa11sp2kjplr0rcpp9hrk.jpg" alt="MODIS Aqua single tile and URI scheme" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your tiles are really just a simple image, but alongside the rest, coordinated by geographic positions and zoom levels, make up what you see when you're looking at a web map like the basemap shown above. The goal of including these smaller individual pieces rather than 1 huge image is that between dealing with the entire globe, the different zoom levels available, and the resolutions available beyond that, we're talking about gigabytes upon gigabytes of image assets that just wouldn't be reliable or realistic to serve as a whole.&lt;/p&gt;

&lt;p&gt;Once you've established your basemap, you can then overlay additional layers using more imagery, vector tiles, or datapoints that get transformed to layers. In the screenshot below, we're zoomed in beyond the highest resolution of our basemap. Notice though the imagery on the left, is an individual overlay tile from &lt;a href="http://blog.digitalglobe.com/news/open-data-response-for-the-california-wildfires/" rel="noopener noreferrer"&gt;Digital Globe&lt;/a&gt; that provides us with a higher resolution of part of the area surrounding the fire zone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff4o3u5eg4f383k0swz28.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff4o3u5eg4f383k0swz28.jpg" alt="MODIS Aqua with tile overlay from Digital Globe" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another example on top of that is adding points representing fires collected from NASA's&lt;a href="https://earthdata.nasa.gov/earth-observation-data/near-real-time/download-nrt-data/viirs-nrt" rel="noopener noreferrer"&gt; VIIRS&lt;/a&gt; imagery.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiw8e3pmfsi5hxpdbeqab.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fiw8e3pmfsi5hxpdbeqab.jpg" alt="MODIS Aqua with VIIRS fire datapoint layer" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows us to have the context of the basemap as well as being able to cast any type of data we'd like to better understand its effects.&lt;/p&gt;

&lt;p&gt;In addition to the VIIRS data, there are many sources of imagery, vector tiles, and datasets published by governments and municipalities that you can use to help build interesting maps and data visualizations. NASA is one good source of these types of assets, but many commercial providers release &lt;a href="https://www.digitalglobe.com/ecosystem/open-data" rel="noopener noreferrer"&gt;open access to disaster datasets&lt;/a&gt; that help others build solutions around relief efforts.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's this about drawing stuff?
&lt;/h3&gt;

&lt;p&gt;Usually when people use maps, they want to look at points of interest. Drawing gives us the ability to frame those areas of interest with different drawing tools such as creating a rectangle using a bounding box tool or drawing a circle. These are simple shapes, but those shapes represent a geographic space that can then be used to gather data about that area.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkpxzc2y200w207d79wcu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkpxzc2y200w207d79wcu.jpg" alt="Rectangular bounding box around Alexandria, VA" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  React ❤️ Leaflet
&lt;/h1&gt;

&lt;p&gt;Leaflet in itself gives you a lot to work with, but there's still a lot of manual effort that goes along with it. If you're used to building a React app, you're probably not as used to building an entire UI using nothing but APIs based on the browser's window, and this is where&lt;a href="https://react-leaflet.js.org/" rel="noopener noreferrer"&gt; React Leaflet&lt;/a&gt; shines.&lt;/p&gt;

&lt;p&gt;React Leaflet is a React library that takes the map building and bundles it into intuitive components that represents those parts of the map. Consider the above, where we talked about your basemap and layers to along with it, you might see it looking something along the lines of:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0zdzdvxdlpl9syhpxarz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0zdzdvxdlpl9syhpxarz.png" alt="Pseudo map component code" width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While you would probably expect that it's not &lt;em&gt;as&lt;/em&gt; flexible as utilizing the Leaflet APIs directly, this completely opens up one's world to being able to easily spin up simple map solutions in an intuitive way without all the effort. After all, at that point, you're spinning up a React app which you're probably already familiar with.&lt;/p&gt;

&lt;h1&gt;
  
  
  Taking it a bit further with Gatsby
&lt;/h1&gt;

&lt;p&gt;You want it easier, you say? You want me to build the map for you, you say? Well, you're in luck! First, let's give a brief introduction to another tool.&lt;/p&gt;

&lt;p&gt;For the unfamiliar,&lt;a href="https://www.gatsbyjs.org/" rel="noopener noreferrer"&gt; Gatsby&lt;/a&gt; is a javascript framework that allows developers to easily spin up full, completely working React applications in a matter of minutes. They have all the nuts and bolts in place and moved out of the way to let you do what you do best: focus on the important parts of your application.&lt;/p&gt;

&lt;p&gt;The beautiful part about Gatsby is that it supports extensions of their default installation which they call &lt;em&gt;Starters&lt;/em&gt;. What better way to make it easier for people to spin up maps than to create a Gatsby Starter?&lt;/p&gt;

&lt;h1&gt;
  
  
  Gatsby Starter Leaflet
&lt;/h1&gt;

&lt;p&gt;Combining the ease of a Gatsby Starter and the flexibility of Leaflet, we have&lt;a href="https://github.com/colbyfayock/gatsby-starter-leaflet" rel="noopener noreferrer"&gt; Gatsby Starter Leaflet&lt;/a&gt;. This simple tool allows you to scaffold a new React application running Leaflet along side React Leaflet in the matter of seconds (or minutes depending on your computer).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp9jjupou7fcqe9siuouk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp9jjupou7fcqe9siuouk.jpg" alt="Starting page for Gatsby Starter Leaflet" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With&lt;a href="https://github.com/colbyfayock/gatsby-starter-leaflet" rel="noopener noreferrer"&gt; a few basic commands&lt;/a&gt;, including installing your dependencies, you have an app that's ready for you to start building on top of to create maps that will save the world. Even better, it includes some out of the box integrations like &lt;a href="https://www.openstreetmap.org/" rel="noopener noreferrer"&gt;OpenStreetMap&lt;/a&gt; and an easy to setup map service configuration to the foundational React Leaflet component APIs that allow you to easily get product and have more flexibility to create smarter Mapping apps.&lt;/p&gt;

&lt;h1&gt;
  
  
  There's gotta be some downsides...
&lt;/h1&gt;

&lt;p&gt;No library or framework isn't without its downsides. The more complicated your mapping application gets, the more pain points you run into. Here are a few from our experience that might help you settle in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjl5f2e4md87lsgmqweyp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjl5f2e4md87lsgmqweyp.gif" alt="Bob Kelso - Scrubs" width="400" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Leaflet - from the Window to React
&lt;/h1&gt;

&lt;p&gt;Trying to manage state and the lifecycle between your Leaflet map and your React components can prove to be tricky. Trying to constantly maintain and update your component using props will immediately start to create issues between stale map state or memory leaks due to maps not properly unmounting when the component does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advice:&lt;/strong&gt; mount your map with React, interact with it using the native Leaflet API. Once your map is rendered and settled down, you can use Leaflet to fly your user around the world and draw on your map without running into the state issues of multiple component renders.&lt;/p&gt;

&lt;h1&gt;
  
  
  Limited Use of Public Tiles
&lt;/h1&gt;

&lt;p&gt;While there are a few tiling services available that allow you to easily plug in and create a basemap, not all of these are actually intended to be heavily used. Take for instance OpenStreetMap, while you may be able to play around and develop basic solutions on their public endpoint, heavy use will be throttled and potentially blocked without explicit permission from those who maintain their servers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advice&lt;/strong&gt;: when you're just starting out playing around, you shouldn't have to worry too much. Worst case the maps will be a little slow to download. As your application starts to get more traffic, you'll want to look into &lt;a href="https://github.com/Overv/openstreetmap-tile-server" rel="noopener noreferrer"&gt;spinning up your own tiling service&lt;/a&gt; or paying for an out of the box solution such as &lt;a href="https://www.mapbox.com/" rel="noopener noreferrer"&gt;Mapbox&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Get mapping!
&lt;/h1&gt;

&lt;p&gt;It has never been easier to build a map-based web application. There is enough tooling, documentation, and public data available to help you get off the ground and start building maps to explore our world in the time it takes you to set up a blog or static website. So what are you waiting for?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6lqx3ujn3gq0g4r4b04r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6lqx3ujn3gq0g4r4b04r.jpg" alt="Go explore with Dora!" width="800" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Get more content straight your inbox!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐦 &lt;a href="https://twitter.com/colbyfayock" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📹 &lt;a href="https://youtube.com/colbyfayock" rel="noopener noreferrer"&gt;Subscribe to my Youtube Channel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🗞️ &lt;a href="https://www.colbyfayock.com/newsletter/" rel="noopener noreferrer"&gt;Sign up for my Newsletter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Originally published on Oct 24, 2019 at &lt;a href="https://www.element84.com/blog/mapping-with-leaflet-and-react" rel="noopener noreferrer"&gt;element84.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mapping</category>
      <category>leaflet</category>
      <category>react</category>
      <category>gatsby</category>
    </item>
  </channel>
</rss>
