<?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>Forem: Daniel Stout</title>
    <description>The latest articles on Forem by Daniel Stout (@stoutlabs).</description>
    <link>https://forem.com/stoutlabs</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%2F78107%2F87127cb7-4c1c-481f-81fc-c8172d8b10c4.jpg</url>
      <title>Forem: Daniel Stout</title>
      <link>https://forem.com/stoutlabs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/stoutlabs"/>
    <language>en</language>
    <item>
      <title>Create an Animated FAQs Component with styled-components, react-spring, and React Hooks</title>
      <dc:creator>Daniel Stout</dc:creator>
      <pubDate>Wed, 28 Aug 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/stoutlabs/create-an-animated-faqs-component-with-styled-components-react-spring-and-react-hooks-182b</link>
      <guid>https://forem.com/stoutlabs/create-an-animated-faqs-component-with-styled-components-react-spring-and-react-hooks-182b</guid>
      <description>&lt;p&gt;In this post, we are going to build something I recently created for a client site: an animated FAQs (Frequently Asked Questions) component. It's simple enough to write a tutorial about, while also showing some pretty powerful tools to use in your projects. This is going to be a long post, so let's get right to it!&lt;/p&gt;

&lt;p&gt;Here's a quick demo of what we'll make:&lt;br&gt;
&lt;a href="https://stoutlabs-faqs-demo.netlify.com/"&gt;FAQs Demo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: To follow along with this tutorial, you need a React-based site set up and ready to edit. Based on the topic of this post, I will assume that you don't need help getting to that point. 😂 (I just used a &lt;a href="https://www.gatsby.org/"&gt;Gatsby.js&lt;/a&gt; default starter for the demo.)&lt;/p&gt;
&lt;h2&gt;
  
  
  Install Libraries
&lt;/h2&gt;

&lt;p&gt;To create this FAQs component, we are going to make use of two outstanding React libraries, &lt;code&gt;react-spring&lt;/code&gt; and &lt;code&gt;styled-components&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.react-spring.io/"&gt;react-spring&lt;/a&gt; is a powerful and easy to implement animation library built for use within React. We're just barely making use of it in this post, but it's capable of extremely advanced animation sequences. Be sure to &lt;a href="https://www.react-spring.io/docs/"&gt;check out their docs&lt;/a&gt; and &lt;a href="https://www.react-spring.io/docs/hooks/examples"&gt;examples&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.styled-components.com/"&gt;styled-components&lt;/a&gt; is an amazing CSS-in-JS library that I use with nearly every React project I work on. There are other similar solutions out there, and I have tried most of them more than once... but &lt;code&gt;styled-components&lt;/code&gt; continues to be my favorite.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's install both of those now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn add react-spring styled-components
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Afterwards, you will likely need to configure &lt;code&gt;styled-components&lt;/code&gt; to work with your React site. For example, in a Gatsby site we would need to install an additional Gatsby plugin, and modify the &lt;code&gt;gatsby-config.js&lt;/code&gt; file. I wrote a full post on &lt;a href="https://alligator.io/gatsbyjs/using-styled-components-in-gatsbyjs/"&gt;using styled-components with Gatsby&lt;/a&gt; at Alligator.io, if you're interested.&lt;/p&gt;

&lt;p&gt;We are also going to make use of React's new &lt;code&gt;Hooks&lt;/code&gt; feature, so be sure that you are using React version &lt;code&gt;16.8.0&lt;/code&gt; or higher. (At the time of writing this post, React is at version &lt;code&gt;16.9.0&lt;/code&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Basic Component(s)
&lt;/h2&gt;

&lt;p&gt;Let's first set up a new directory inside our project at &lt;code&gt;/src/components/Faqs/&lt;/code&gt;. Inside this directory, let's create two new files:&lt;/p&gt;

&lt;h3&gt;
  
  
  Faq.js
&lt;/h3&gt;

&lt;p&gt;This file is a React component that functions as an individual FAQ question/answer pair.&lt;/p&gt;

&lt;h4&gt;
  
  
  /src/components/Faqs/Faq.js
&lt;/h4&gt;



&lt;div class="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;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&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;Faq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toggleOpen&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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="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;onClick=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;toggleOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&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;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s2"&gt;"faq-question"&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;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          Q: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;question&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;span&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;&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="s2"&gt;"faq-answer"&lt;/span&gt; 
        &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;block&lt;/span&gt;&lt;span class="dl"&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="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&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;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          A: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;answer&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;span&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;&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;default&lt;/span&gt; &lt;span class="nx"&gt;Faq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, we are making use of the &lt;code&gt;useState&lt;/code&gt; hook in React to track an open/closed state for this component. It doesn't really do much yet, but soon we'll animate the showing &amp;amp; hiding of the answer using &lt;code&gt;react-spring&lt;/code&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  FaqsList.js
&lt;/h3&gt;

&lt;p&gt;This file is just a simple React component that will function as a container to hold our list of FAQs:&lt;/p&gt;

&lt;h4&gt;
  
  
  /src/components/Faqs/FaqsList.js
&lt;/h4&gt;



&lt;div class="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;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Faq&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Faq&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// this data could come from anywhere&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;faqsData&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="na"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What does FAQ stand for?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Frequently Asked Question&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What is the best ice cream flavor?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Coffee with fudge ripple, or homemade strawberry.&lt;/span&gt;&lt;span class="dl"&gt;"&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;FaqsList&lt;/span&gt; &lt;span class="o"&gt;=&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="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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;faqsData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;faq&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Faq&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;faq_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;question=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;faq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;answer=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;faq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;answer&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;))&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;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;default&lt;/span&gt; &lt;span class="nx"&gt;FaqsList&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;faqsData&lt;/code&gt; array of FAQ objects above. This data could come from anywhere (your CMS, an API, etc), but for demo purposes I just hard-coded some data in.&lt;/p&gt;

&lt;p&gt;Ok, now that we have our basic components set up... let's add the fun stuff: styles and animation!&lt;/p&gt;

&lt;h2&gt;
  
  
  Styling With styled-components
&lt;/h2&gt;

&lt;p&gt;Let's create some basic styles for our &lt;code&gt;FaqsList&lt;/code&gt; and &lt;code&gt;Faq&lt;/code&gt; components. Create a new &lt;code&gt;faq-styles.js&lt;/code&gt; file in the same directory as our components, and insert this code:&lt;/p&gt;

&lt;h4&gt;
  
  
  /src/components/Faqs/faq-styles.js
&lt;/h4&gt;



&lt;div class="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;styled&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;styled-components&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StyledFaq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
  cursor: pointer;
  margin: 0 0 10px;

  div.faq-question {
    font-size: 125%;
    font-weight: 800;
    margin: 0 0 5px;
  }

  div.faq-answer {
    background: #fff;
    overflow: hidden;

    span {
      display: block; 
      padding: 20px 10px;
    }
  }
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;StyledFaqsList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
  background: #efefef;
  margin: 20px 0;
  padding: 1rem;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice how we're exporting each of these? This will allow us to import them from the component files we created above. This method will keep all of your FAQs styles all in one location, for easier customizing later on.&lt;/p&gt;

&lt;p&gt;Note: This is my typical pattern when making "folder-based" components that I plan to re-use in other locations. &lt;em&gt;A lot of folks seem to think that styles must be within each component file when using &lt;code&gt;CSS-in-JS&lt;/code&gt; solutions... but that is incorrect!&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adjust the Components
&lt;/h3&gt;

&lt;p&gt;Let's adjust our &lt;code&gt;Faq.js&lt;/code&gt; and &lt;code&gt;FaqsList.js&lt;/code&gt; components to make use of these new styles:&lt;/p&gt;

&lt;h4&gt;
  
  
  /src/components/Faqs/Faq.js
&lt;/h4&gt;



&lt;div class="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;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StyledFaq&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./faqStyles&lt;/span&gt;&lt;span class="dl"&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;Faq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toggleOpen&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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="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="nc"&gt;StyledFaq&lt;/span&gt; &lt;span class="na"&gt;onClick=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;toggleOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&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;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s2"&gt;"faq-question"&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;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Q: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;question&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;span&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;&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="s2"&gt;"faq-answer"&lt;/span&gt;
        &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;block&lt;/span&gt;&lt;span class="dl"&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="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&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;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;A: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;answer&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;span&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;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;StyledFaq&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;default&lt;/span&gt; &lt;span class="nx"&gt;Faq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;All we did above was add an import statement for &lt;code&gt;StyledFaq&lt;/code&gt;, and then swap out the outer &lt;code&gt;div&lt;/code&gt; element with our imported styled component. Make sense?&lt;/p&gt;

&lt;p&gt;Next, we'll do the same thing with the &lt;code&gt;FaqsList&lt;/code&gt; component:&lt;/p&gt;

&lt;h4&gt;
  
  
  /src/components/Faqs/FaqsList.js
&lt;/h4&gt;



&lt;div class="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;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Faq&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./Faq&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StyledFaqsList&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./faqStyles&lt;/span&gt;&lt;span class="dl"&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;faqsData&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="na"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What does FAQ stand for?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Frequently Asked Question!&lt;/span&gt;&lt;span class="dl"&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="na"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What's the best ice cream flavor?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Coffee with fudge ripple, or homemade strawberry.&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FaqsList&lt;/span&gt; &lt;span class="o"&gt;=&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StyledFaqsList&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;faqsData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;faq&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Faq&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;faq_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;question=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;faq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;answer=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;faq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;answer&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;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;StyledFaqsList&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;default&lt;/span&gt; &lt;span class="nx"&gt;FaqsList&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You should now have a basic styled FAQs list displaying, with each FAQ item showing/hiding the answer when clicked. &lt;em&gt;If yours isn't doing that, I'll post a link to the full source at the end⁠ — so don't panic!&lt;/em&gt; 😎&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Animation With react-spring
&lt;/h2&gt;

&lt;p&gt;Let's add some animation to this with &lt;code&gt;react-spring&lt;/code&gt;! To keep it really simple for this post, we will just animate the showing/hiding of the answer portion of each FAQ when clicked.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(And yes, my CSS warrior friends... we could do something like this with pure CSS ⁠— but I want to show usage of react-spring in this post!)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But first, we need to add in a tiny npm package to help us measure the height of our answers. We need that info to tell &lt;code&gt;react-spring&lt;/code&gt; what the height is when an answer is in the 'open' state. There's a few available options for this, but I'm going to use &lt;a href="https://www.npmjs.com/package/react-resize-aware"&gt;react-resize-aware&lt;/a&gt; - since it has an easy-to-use hooks-based solution.&lt;/p&gt;

&lt;p&gt;Add it to your project, like usual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn add react-resize-aware
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we just need to edit the &lt;code&gt;Faq.js&lt;/code&gt; component to add the animations. Below is the updated code:&lt;/p&gt;

&lt;h4&gt;
  
  
  /src/components/Faqs/Faq.js
&lt;/h4&gt;



&lt;div class="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;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useSpring&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;animated&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-spring&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useResizeAware&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-resize-aware&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StyledFaq&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./faqStyles&lt;/span&gt;&lt;span class="dl"&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;Faq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toggleOpen&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;resizeListener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useResizeAware&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;animProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useSpring&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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="nc"&gt;StyledFaq&lt;/span&gt; &lt;span class="na"&gt;onClick=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;toggleOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&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;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s2"&gt;"faq-question"&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;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Q: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;question&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;span&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;animated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s2"&gt;"faq-answer"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;animProps&lt;/span&gt; &lt;span class="p"&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;span&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;relative&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;resizeListener&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; A: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;answer&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;span&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;animated&lt;/span&gt;&lt;span class="p"&gt;.&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;StyledFaq&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;default&lt;/span&gt; &lt;span class="nx"&gt;Faq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To explain a little more, we did the following things above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Imported the two packages we already installed, &lt;code&gt;react-spring&lt;/code&gt; and &lt;code&gt;react-resize-aware&lt;/code&gt;. We destructured &lt;code&gt;useSpring&lt;/code&gt; and &lt;code&gt;animated&lt;/code&gt; from &lt;code&gt;react-spring&lt;/code&gt; so they're easier to use.&lt;/li&gt;
&lt;li&gt;Created a new variable for our animation configuration settings, using the &lt;code&gt;useSpring&lt;/code&gt; Hook from &lt;code&gt;react-spring&lt;/code&gt;. Notice that we set initial values of &lt;code&gt;0&lt;/code&gt; for the opacity and height, and then our measured &lt;code&gt;height&lt;/code&gt; value is used to set the height when the answer is shown. (And of course, opacity is set to 1.)&lt;/li&gt;
&lt;li&gt;Converted the &lt;code&gt;faq-answer&lt;/code&gt; div into a react-spring &lt;code&gt;animated.div&lt;/code&gt; element, and spread the values of &lt;code&gt;animProps&lt;/code&gt; out into the &lt;code&gt;styles&lt;/code&gt; prop.&lt;/li&gt;
&lt;li&gt;Added a &lt;code&gt;position: relative&lt;/code&gt; style to the answer's inner &lt;code&gt;span&lt;/code&gt; tag. This is required by &lt;code&gt;react-resize-aware&lt;/code&gt; to properly measure the element on load. (See next item.)&lt;/li&gt;
&lt;li&gt;Added a &lt;code&gt;resizeListener&lt;/code&gt; into our answer's inner span. This is part of &lt;code&gt;react-resize-aware&lt;/code&gt;, and it measures the answer's height when loaded. (It's essentially an invisible div that returns its width and height via a custom React Hook... so it works perfectly in our stateless component!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Go ahead and give it a try, if you haven't already. Each FAQ item should now animate open when clicked, and should animate back to closed if clicked again. Pretty cool, huh? You can now re-use this component in any of your sites, and you only need to edit the styles/animations to fit your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;We are finished! I hope that helps a few of you out there, and maybe even gives you some ideas to try on your own!&lt;/p&gt;

&lt;h3&gt;
  
  
  Preview/Download Source:
&lt;/h3&gt;

&lt;p&gt;Demo here: &lt;a href="https://stoutlabs-faqs-demo.netlify.com/"&gt;https://stoutlabs-faqs-demo.netlify.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Demo Source on Github: &lt;a href="https://github.com/stoutlabs/demo-spring-hooks"&gt;https://github.com/stoutlabs/demo-spring-hooks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am planning to start writing more... so I'll catch you on the next post!  💜&lt;/p&gt;

</description>
      <category>react</category>
      <category>reactspring</category>
      <category>styledcomponents</category>
      <category>reacthooks</category>
    </item>
    <item>
      <title>My Docker Setup For GatsbyJS (and NextJS)</title>
      <dc:creator>Daniel Stout</dc:creator>
      <pubDate>Wed, 06 Feb 2019 13:56:43 +0000</pubDate>
      <link>https://forem.com/stoutlabs/my-docker-setup-for-gatsbyjs-and-nextjs-5gao</link>
      <guid>https://forem.com/stoutlabs/my-docker-setup-for-gatsbyjs-and-nextjs-5gao</guid>
      <description>&lt;p&gt;Update: Alpine made a couple changes that affect this post, and &lt;a href="https://dev.to/stuckj/comment/bej8"&gt;a helpful comment below&lt;/a&gt; will clear up the issue(s) caused from that. Thanks Jonathan! I've also fixed the example code.&lt;/p&gt;

&lt;p&gt;Update #2: It seems that Hot Module Reloading is currently borked with this in Windows. I'll post an update if/when that is fixed!&lt;/p&gt;

&lt;p&gt;Update #3: If you're still experiencing issues, another comment below might get you back on track: &lt;a href="https://dev.to/ivorsco77/comment/ia43"&gt;HERE&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker is Fantastic
&lt;/h2&gt;

&lt;p&gt;I'm probably late to the party on this one, but I recently started using &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; as a part of my development workflow. I absolutely love it, and I feel that all developers should at least tinker with a basic tutorial somewhere. Trust me, it's a rabbit hole worth exploring!&lt;/p&gt;

&lt;h2&gt;
  
  
  But... There Was a Minor Hitch
&lt;/h2&gt;

&lt;p&gt;While going through a some of my recent Gatsby and NextJS projects this week to "Dockerize" them, I noticed that there didn't seem to be much information readily available for making that happen. &lt;/p&gt;

&lt;p&gt;Gatsby does offer &lt;a href="https://github.com/gatsbyjs/gatsby-docker"&gt;a Docker setup&lt;/a&gt; within their repo (based on alpine:edge), but to be blunt: it seemed needlessly complicated and vague, and I could not make it work for my purposes. (I think it's only meant to serve a site, post-build.) &lt;/p&gt;

&lt;p&gt;So, I decided to figure out how to create a custom one from an official node:alpine (latest) image... just something to use for a quick dev environment setup regardless of which computer I'm using. (If I wanted to deploy somewhere other than Netlify, I could quickly add an Nginx image/service and a super basic conf file.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Solved!
&lt;/h2&gt;

&lt;p&gt;After hours of learning, research, and experimenting (and possibly some frustration), I present you with my version of a working Dockerfile! It will create a fully functional Docker image that installs all the required packages in Apline Linux (latest) for building Gatsby (and NextJS) sites and apps.&lt;/p&gt;

&lt;p&gt;(Note: For NextJS sites, I simply change the final CMD and the port(s) to whatever I'm using for the site/app... usually 8080.)&lt;/p&gt;

&lt;h4&gt;
  
  
  Dockerfile.dev
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:alpine&lt;/span&gt;

&lt;span class="c"&gt;# Also exposing VSCode debug ports&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8000 9929 9230&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;  apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; python make g++ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  apk add vips-dev fftw-dev &lt;span class="nt"&gt;--update-cache&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nt"&gt;--repository&lt;/span&gt; http://dl-3.alpinelinux.org/alpine/edge/community &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="nt"&gt;--repository&lt;/span&gt; http://dl-3.alpinelinux.org/alpine/edge/main &lt;span class="se"&gt;\
&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-fR&lt;/span&gt; /var/cache/apk/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; gatsby-cli

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./package.json .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn cache clean
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["yarn", "develop", "-H", "0.0.0.0" ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  docker-compose.yml
&lt;/h4&gt;

&lt;p&gt;(Note the setting of &lt;code&gt;GATSBY_WEBPACK_PUBLICPATH&lt;/code&gt; - this seemed to fix any HMR issues I was having when editing code.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;dockerfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Dockerfile.dev&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8000:8000"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9929:9929"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9230:9230"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/app/node_modules&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/app&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=development&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GATSBY_WEBPACK_PUBLICPATH=/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll probably want to throw a &lt;code&gt;.dockerignore&lt;/code&gt; file into the project directory too, to ignore things like ./node_modules, ./cache, ./public, any .DS_Store files, etc. (Much like a &lt;code&gt;.gitignore&lt;/code&gt; file.)&lt;/p&gt;

&lt;p&gt;To run it, from the project's root directory run:&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="nv"&gt;$ &lt;/span&gt;docker-compose up &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running that, I'm ready to work... whether I'm on my Macbook Pro or on my Windows desktop. Hopefully this helps you too!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>gatsby</category>
      <category>nextjs</category>
      <category>workflow</category>
    </item>
    <item>
      <title>Speed Tip: Use Typefaces.js in Gatsby to Locally Host Fonts</title>
      <dc:creator>Daniel Stout</dc:creator>
      <pubDate>Wed, 22 Aug 2018 17:53:44 +0000</pubDate>
      <link>https://forem.com/stoutlabs/speed-tip-use-typefacesjs-in-gatsby-to-locally-host-fonts-6om</link>
      <guid>https://forem.com/stoutlabs/speed-tip-use-typefacesjs-in-gatsby-to-locally-host-fonts-6om</guid>
      <description>&lt;p&gt;Since launching my new &lt;a href="https://next.gatsbyjs.org"&gt;Gatsby&lt;/a&gt;-powered website, I noticed that there was only one thing still slowing down the load times: importing fontfaces via Google Fonts! Even though font files are usually relatively small, these imports cause an extra trip to Google's servers... and as a result, a tiny load-blocking delay occurs. (Especially on slow connections.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing Typefaces.js
&lt;/h3&gt;

&lt;p&gt;Self-hosting fonts has always been a bit of a mess in the past, so most folks (including myself) resorted to just importing straight from Google Fonts... that's what they suggest, after all!&lt;/p&gt;

&lt;p&gt;Thankfully, there's a more elegant JS soution available: the &lt;a href="https://github.com/KyleAMathews/typefaces"&gt;Typefaces.js&lt;/a&gt; package from Kyle Mathews. (Yes, one of the creators of Gatsby.) Assuming your site or app's build process uses Webpack with loaders for CSS and fonts, it's ridiculously easy to use. In my case, I wanted to use it in Gatsby...&lt;/p&gt;

&lt;h4&gt;
  
  
  Using Typefaces.js In Gatsby
&lt;/h4&gt;

&lt;p&gt;This is all you have to do:&lt;/p&gt;

&lt;h5&gt;
  
  
  1. Locate the Typeface files on NPM for font(s) needed.
&lt;/h5&gt;

&lt;p&gt;In my case, it was: &lt;a href="https://www.npmjs.com/package/typeface-emilys-candy"&gt;Emily's Candy&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/typeface-merriweather"&gt;Merriweather&lt;/a&gt;. &lt;em&gt;Note: All of Google's fonts are available for this on NPM, as Kyle has programatically added them. (Font Squirrel's fonts are in the works too!)&lt;/em&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  2. Install the above files via yarn:
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;yarn&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="nx"&gt;typeface&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;merriweather&lt;/span&gt; &lt;span class="nx"&gt;typeface&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;emilys&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;candy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  3. Remove the previous imports of those fonts.
&lt;/h5&gt;

&lt;p&gt;(Mine were previously imported via an @import in my SCSS)&lt;/p&gt;

&lt;h5&gt;
  
  
  4. Add the following to &lt;code&gt;gatsby-browser.js&lt;/code&gt;:
&lt;/h5&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typeface-emilys-candy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typeface-merriweather&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;or, import in your top-level/layout component(s):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typeface-emilys-candy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;typeface-merriweather&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h5&gt;
  
  
  5. Do a fresh rebuild, and you're done!
&lt;/h5&gt;

&lt;p&gt;The entire process took me around 2 minutes total time, and I shaved an additional ~500ms off my mobile load times in the process. If you haven't already done this on your Gatsby site, I highly recommend it!&lt;/p&gt;

</description>
      <category>websiteoptimization</category>
      <category>gatsbyjs</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
